bzoj1079: [SCOI2008]着色方案 題解

1079: [SCOI2008]着色方案
Description

  有n個木塊排成一行,從左到右依次編號爲1~n。你有k種顏色的油漆,其中第i種顏色的油漆足夠塗ci個木塊。
所有油漆剛好足夠塗滿所有木塊,即c1+c2+…+ck=n。相鄰兩個木塊塗相同色顯得很難看,所以你希望統計任意兩
個相鄰木塊顏色不同的着色方案。

Input

  第一行爲一個正整數k,第二行包含k個整數c1, c2, … , ck。

Output

  輸出一個整數,即方案總數模1,000,000,007的結果。

Sample Input

3
1 2 3

Sample Output

10

HINT

100%的數據滿足:1 <= k <= 15, 1 <= ci <= 5

我們發現K最多隻有5,於是就會想到這樣一個DP:
定義F[L][a][b][c][d][e]表示上一次用的油漆在沒有用的情況下可以刷L個牆,而此時還能刷1個牆的油漆數量有a個,能刷2個牆的油漆數量有b個……能刷5個牆的油漆數量有e個;
此時考慮轉移方程:
如果能刷L-1個牆的油漆數量大於1(也就是說除了上一次用的油漆還有油漆可以用),那麼就有轉移方程(Num[i]爲當前能刷i個牆的油漆數量的個數,A=Num[1],B=Num[2]……E=Num[5]):

F[L][a][b][c][d][e]+=(Num[L-1]-1)*F[L-1][A][B][C][D][E]

同理,用能刷其他個數的牆的油漆轉移方程如下:

F[L][a][b][c][d][e]+=Num[p]*F[p][A][B][C][D][E]

初始狀態就是F[i][0][0][0][0][0]=1
因爲A,B,C,D,E這些量會變化,普通的DP無法完成,所以就會想到用記憶化DFS,那麼最終代碼如下:

#define tt 1000000007
#define Nxt(Row,p) DFS(Row[5],Row[4],Row[3],Row[2],Row[1],p)%tt
……
long long F[16][16][16][16][16][6]//F[a][b][c][d][e][L] 方便起見把L後置
long long DFS(int a,int b,int c,int d,int e,int L){ //記憶化DFS
    if (F[a][b][c][d][e][L]^0) return F[a][b][c][d][e][L];
    long long &Ret=F[a][b][c][d][e][L];
    int Row[6]={0,e,d,c,b,a};
    if (Row[L-1]>1&&L>1) Row[L-1]--,Row[L-2]++,Ret=(Ret+(Row[L-1])*Nxt(Row,L-1))%tt,Row[L-1]++,Row[L-2]--; //F[L][a][b][c][d][e]+=(Num[L-1]-1)*F[L-1][A][B][C][D][E]
    for (int i=1;i<=5;i++){
        if (i==L-1) continue;
        if (Row[i]>0){
            Row[i]--,Row[i-1]++;
            Ret=(Ret+(Row[i]+1)*Nxt(Row,i))%tt; //F[L][a][b][c][d][e]+=Num[p]*F[p][A][B][C][D][E]
            Row[i]++,Row[i-1]--;
        }
    }
    return Ret;
}
int main()
{
    ……
    for (int i=0;i<=5;i++) F[0][0][0][0][0][i]=1;
    ……
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章