题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=6146
分析:这道题有点麻烦啊!貌似是原题,讨论情况好恶心啊。
1、首先呢,我们考虑从左上角出发,先从左往右抓到底,再从右往左抓,因为题目要的是步数最少的,所以不能随便 走。每一步选择有2种可能,所以总的方案数是 b[i] = 2^i (i为列数)
2、我们可以第一列抓完,再抓第二列,也从左上角开始,到第二列有两种可能,到上面的格子和到下面的格子,所以
方案数是 2 * a[i-1] (a[i-1]表示上一列的总方案数)
3、从左上角走,我们可以两列抓完再抓第三列,也就是两列的方案数是 2 * a[i-2],然后因为走到第三列可以上 下,也就是 *2 ,所以总的方案数是 4 * a[i-2] (如果抓完三列及以上再抓第四列(不与上面两种情况一样), 那么终点就不在第四列隔壁了,也就是步数不是最少)
前三点总结:从左上角抓的总方案数就是上面的方案数加起来,因为我们可以从四个角开始抓,所以方案数要乘以4
4、从中间开始抓(2~n-1列),那么我们可以先走左边,但是我们要最后回到这一列的下面,所以走左边只能走到底,再 走回来,也就是第1种情况,然后回到这一列之后,往右边走就可以随便了,所以这种情况是
b[i-1]*a[n-i]*2*2,因为第i-1列可能从上下两位置开始,回来后往右边又可以上下两位置开始,所以乘以4。
同理,右边也一样可推。而且开始第i列也可以上下两个格子开始,所以情况4总的方案数就是
2*((b[i-1]*a[n-i]*4)+(b[n-i]*a[i-1]*4))
代码如下:
#include<bits/stdc++.h> using namespace std; typedef long long LL; const LL mod = 1000000007; LL a[10005],b[10005]; int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); b[1] = 1; for(int i = 2 ; i <= n; i++) b[i] = b[i - 1] * 2 % mod; //a[i]从左上角开始的方案数 memset(a,0,sizeof(a)); a[1] = 1; a[2] = 6; for(int i = 3 ; i <= n ; i++) { a[i] = (2 * a[i - 1]) % mod; // 第一列抓完再抓第二列 a[i] = (a[i] + b[i]) % mod; //从头到尾再从尾到头抓 a[i] = (a[i] + 4 * a[i - 2] %mod) % mod;//两列抓完抓第三列 } LL sum = a[n] * 4 % mod;//四个方向 //统计其他的方法 for(int i = 2 ; i < n; i++) { //从中间开始往两边抓,开始那边只能从头到尾再到头抓 sum = (sum + (((8 * b[i - 1])%mod * a[n - i]) % mod + ((8 * b[n - i])%mod * a[i - 1]) % mod) % mod)%mod; } if(n == 1) sum = 2; printf("%I64d\n",sum); } return 0; }
2017百度之星复赛1003Pokémon GO------hdu6146
原文:http://www.cnblogs.com/maplefighting/p/7398123.html