bzoj1079 [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

直接暴力肯定超時,就可以考慮 dp。
計六維數組 dp表示可以塗一次的還剩多少、兩次…塗五次的還剩多少,最後一維記上一次用的塗幾次的。
那麼就可以轉移了。
值得注意的是,假設上一次用了可塗 a 次的,那麼這個可塗 a 次的就變成了可塗 a-1 次的了,相應維度要減要加,下次選 a-1 次的時候答案要減減。
代碼和網上的都很像

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=1000000007;
long long dp[16][16][16][16][16][6];
int num[6],n;
bool judge[16][16][16][16][16][6];
long long count(int a,int b,int c,int d,int e,int k)
{
    long long t=0;
    if(judge[a][b][c][d][e][k])
        return dp[a][b][c][d][e][k];
    if(!a&&!b&&!c&&!d&&!e)return 1;
    if(a)  
        t+=(a-(k==2))*count(a-1,b,c,d,e,1);  
    if(b)  
        t+=(b-(k==3))*count(a+1,b-1,c,d,e,2);  
    if(c)  
        t+=(c-(k==4))*count(a,b+1,c-1,d,e,3);  
    if(d)  
        t+=(d-(k==5))*count(a,b,c+1,d-1,e,4);  
    if(e)  
        t+=e*count(a,b,c,d+1,e-1,5);  
    judge[a][b][c][d][e][k]=true;
    return dp[a][b][c][d][e][k]=(t%mod);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int t;
        scanf("%d",&t);
        num[t]++;
    }
    long long ans=count(num[1],num[2],num[3],num[4],num[5],0);
    cout<<ans;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章