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

【链接】
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 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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值