【HDU】6146 Pokémon GO

【题意】一个2*n的网格,再保证步数最少的情况下,求从任意格出发遍历完所有格的方案数,格子八连通。n<=10000,T<=100。

【算法】递推,DP

【题解】原题链接:蓝桥杯 格子刷油漆(动态规划)

这类题目最重要的是找到一个可以计算所有情况的状态表示。

对于2*x的网格,a[x]表示从左上角出发遍历完所有格子的方案数,b[x]表示从左上角出发遍历完所有格子并在左下角结束的方案数。

显然,b[x]=2*b[x-1]

先考虑起点在左上角,有三种情况:

①先走到对面(左下角),再往右走,a[x]+=2*a[x-1]。

②终点在对面,a[x]+=b[x]。

③先走到第二列再折返再走到第二列,此时等价于第二列的第一种情况,a[x]+=4*a[x-2]。

公式合并为a[x]=2*a[x-1]+4*a[x-2]+b[x]

一共有四个角,所以ans+=4*a[x]。

再考虑起点在第一行(不包括左右上角),必须要先遍历完一边回到下方再遍历另一边才能保证遍历完全部。

对于先遍历一边的情况,等价于出发后回到下方的b[i],再遍历另一边的情况,等价于从一角出发的a[i]。

所以对于每个中间点i,ans+=2*(2*b[i-1]*2*a[n-i])+2*(2*b[n-i]*2*a[i-1]) 。

ans=16*sigma(b[i-1]*a[n-i])(i=2~n-1)+4*a[n]

---

有取模别写“+=”!

爆long long了要中间多写点取模……2*int是撞在ll枪口上的,多一点就爆了。

---

#include<cstdio>
#define ll long long
const int maxn=10010,MOD=1000000007;
ll a[maxn],b[maxn],n;
int main(){
    b[1]=1;
    for(int i=2;i<=maxn;i++)b[i]=(b[i-1]*2)%MOD;
    a[1]=1;a[2]=6;
    for(int i=3;i<=maxn;i++)a[i]=(2*a[i-1]+b[i]+4*a[i-2])%MOD;
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        ll ans=0;
        for(int i=2;i<=n-1;i++)ans=(ans+16*b[i-1]%MOD*a[n-i])%MOD;
        ans=(ans+4*a[n])%MOD;
        if(n==1)ans=2;
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

能把这个公式换成一个数组的递推公式真是太可怕了。

f[1]=2  f[2]=24  f[3]=96  f[4]=416  f[5]=1536

f[i]=f[i-1]*6-f[i-2]*8-f[i-3]*8+f[i-4]*16  (i>=6)

 

posted @ 2017-08-22 18:05  ONION_CYC  阅读(143)  评论(0编辑  收藏  举报