Description
一个2×n的棋盘,一个格子只能走向与其某维坐标差1的格子,问有多少条路径可以走遍所有格子
Input
第一行一整数
Output
对于每组用例,输出方案数,结果模109+7
Sample Input
3
1
2
3
Sample Output
2
24
96
Solution
令f(n)为从2×n的棋盘左上角出发,遍历所有格子后回到左下角的方案数,g(n)为从2×n的棋盘左上角出发,遍历所有格子的方案数,则f(1)=1,g(1)=1,g(2)=6(2×2的棋盘任意两点可达,故方案数即为除左上角的三个格子的排列数)
先求f(n),为使从左上角出发可以回到左下角,左上角第一步需要走到第二列的某个格子,然后遍历后n−2列后回到第二列的另一个格子然后再回到左下角,故有f(n)=2⋅f(n−1)
再求g(n),考虑左下角的格子是第几个被经过的,如果是第二个被经过的,那么第一列被遍历,要走到第二列的某个格子然后遍历后n−1列,方案数2⋅g(n−1),如果是第三个被经过的,那么第一步是从左上角走到第二列的某个格子,然后从这个格子走到左下角,再从左下角走到第二列剩下的一个格子里,再从这个格子走到第三列某个格子去遍历后n−2个格子,方案数4⋅g(n−2),否则左下角只能是最后一个被经过的,方案数即为从左上角遍历所有格子回到左下角的方案数f(n),故有g(n)=f(n)+2⋅g(n−1)+4⋅g(n−2)
求出f(n),g(n)后,考虑求答案,如果起点在四个角的某一个,方案数为g(n),对答案贡献4⋅g(n),如果起点在中间,枚举起点所在列i,第
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define maxn 10005
#define mod 1000000007
ll f[maxn],g[maxn];
void init(int n=10000)
{
f[1]=1;
for(int i=2;i<=10000;i++)f[i]=f[i-1]*2%mod;
g[1]=1;g[2]=6;
for(int i=3;i<=10000;i++)g[i]=(f[i-1]*2+g[i-1]*2+g[i-2]*4)%mod;
}
int main()
{
init();
int T,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
if(n==1)printf("2\n");
else
{
ll ans=g[n]*4%mod;
for(int i=2;i<n;i++)
ans=(ans+(f[i]*g[n-i]+f[n-i+1]*g[i-1])*4%mod)%mod;
printf("%I64d\n",ans);
}
}
return 0;
}