HDU6146(2017百度之星程序设计大赛

来源:互联网 发布:个人网络循环贷款利率 编辑:程序博客网 时间:2024/05/21 11:06

【链接】
hdu6146

【题目大意】

给你一个2n的矩阵,你可以从一个格子移动到一个相邻的至少有一个公共点的格子,求从任意一个格子开始遍历所有节点一次的方案数。

【解题报告】

这题其实就是一道DP题就是想转移方程有点复杂。

首先从简单的想,假设求从一个矩阵的一个角遍历所有节点一次且回到同一列的另一个节点的方案数。

那么很容易想到转移方程,定义bi表示目前推到的矩阵大小为2i时,满足以上条件的方案数。

b1=1 bi=bi12(i>1)

所以bi=2i1

进一步想,假设求从一个矩阵的一个角遍历所有节点一次的方案数。

经过仔细的思考,定义ai表示目前推到的矩阵大小为2i时,满足以上条件的方案数。

a1=1 a2=6

所以ai的转移方程就是ai=bi+2ai1+4ai2(i>2)

bi表示已确定已i个列的走法

2ai1表示已确定i1个列的走法,在增加一列(增加的列不能在开头或末尾),相当于增加两个节点所以就是原来方案数(即ai1)2

4ai2表示已确定i2个列的走法,在增加相邻两列(增加的列不能在开头或末尾),先遍历前一列的一个点,之后遍历后一列的一个点,再返回前一列遍历另一个点的方案有4种,所以就是原来方案数(即ai2)4

然后就可以推出从2n的矩阵的四个角走完遍历所有节点一次的方案数即4an

然后就只剩考虑起点不是四个角的情况,我们可以枚举开始的列,定义fi表示以第i列为起点所以转移方程就是

fi=24(ai1bni+bi1ani)(1<i<n)

2表示当前列有两个起点可以作为起点,4表示两列之间可以互相走到的方案数。

所以答案就是n1i=2fi+4an

#include<cstdio>#define LL long longusing namespace std;const int maxn=10005,tt=1000000007;int T,n,ans,a[maxn],b[maxn];inline int Read(){    int res=0;    char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') res=res*10+ch-48,ch=getchar();    return res;}void Work(){    n=Read();    if (n==1) {printf("2\n"); return;}    ans=(LL)4*a[n]%tt;    for (int i=2; i<n; i++)     ans=(((LL)ans+(LL)8*b[i-1]%tt*a[n-i]%tt)%tt+(LL)8*a[i-1]%tt*b[n-i]%tt)%tt;    printf("%d\n",ans);}int main(){    freopen("6146.in","r",stdin);    freopen("6146.out","w",stdout);    b[1]=1; for (int i=2; i<=10000; i++) b[i]=b[i-1]*2%tt;    a[1]=1; a[2]=6; for (int i=3; i<=10000; i++) a[i]=(b[i]+(LL)a[i-1]*2+(LL)a[i-2]*4)%tt;    T=Read(); while (T--) Work();    return 0;}