1. 程式人生 > >【HDU】6146 Pokémon GO

【HDU】6146 Pokémon GO

fin strong fine http 格子 tdi for 最重要的 tro

【題意】一個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)

【HDU】6146 Pokémon GO