您的位置:首页 > 编程语言 > Go语言

HDU 6146 Pokémon GO(dp+组合数学)

2018-01-21 19:21 323 查看
Description

一个2×n的棋盘,一个格子只能走向与其某维坐标差1的格子,问有多少条路径可以走遍所有格子

Input

第一行一整数T表示用例组数,每组用例输入一个整数n(1≤T≤100,1≤n≤10000)

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,第i列可以有两个起点,如果先往左走那么需要遍历前i列后回到第i列然后走到第i+1列后遍历后n−i列,方案数4⋅f(i)⋅g(n−i),如果先往右走那么需要遍历后n−i+1列后回到第i列然后走到第i−1列后遍历前i−1列,方案数4⋅f(n−i+1)⋅g(i−1),故ans=4⋅g(n)+4⋅∑i=2n−1(f(i)⋅g(n−i)+f(n−i+1)⋅g(i−1))

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
*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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: