【链接】
hdu6146
【题目大意】
给你一个 2∗n 的矩阵,你可以从一个格子移动到一个相邻的至少有一个公共点的格子,求从任意一个格子开始遍历所有节点一次的方案数。
【解题报告】
这题其实就是一道DP题就是想转移方程有点复杂。
首先从简单的想,假设求从一个矩阵的一个角遍历所有节点一次且回到同一列的另一个节点的方案数。
那么很容易想到转移方程,定义 bi 表示目前推到的矩阵大小为 2∗i 时,满足以上条件的方案数。
b1=1 bi=bi−1∗2(i>1)
所以 bi=2i−1
进一步想,假设求从一个矩阵的一个角遍历所有节点一次的方案数。
经过仔细的思考,定义 ai 表示目前推到的矩阵大小为 2∗i 时,满足以上条件的方案数。
a1=1 a2=6
所以 ai 的转移方程就是 ai=bi+2∗ai−1+4∗ai−2(i>2)
bi 表示已确定已 i 个列的走法
4∗ai−2 表示已确定 i−2 个列的走法,在增加相邻两列(增加的列不能在开头或末尾),先遍历前一列的一个点,之后遍历后一列的一个点,再返回前一列遍历另一个点的方案有4种,所以就是原来方案数(即 ai−2 ) ∗4
然后就可以推出从 2∗n 的矩阵的四个角走完遍历所有节点一次的方案数即 4∗an
然后就只剩考虑起点不是四个角的情况,我们可以枚举开始的列,定义 fi 表示以第 i 列为起点所以转移方程就是
2表示当前列有两个起点可以作为起点,4表示两列之间可以互相走到的方案数。
所以答案就是 ∑n−1i=2fi+4∗an
#include<cstdio>
#define LL long long
using 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;
}