【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); whileView Code(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; }
能把這個公式換成一個數組的遞推公式真是太可怕了。
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)
【HDU】6146 Pokémon GO