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

HDU6146(2017百度之星程序设计大赛 - 复赛)[Pokémon GO]--DP

2017-08-22 21:45 441 查看
【链接】

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个列的走法

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

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

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

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

fi=2∗4∗(ai−1∗bn−i+bi−1∗an−i)(1<i<n)

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