1. 程式人生 > >bzoj1079: [SCOI2008]著色方案(dp)

bzoj1079: [SCOI2008]著色方案(dp)

pan str 其中 bool sample 100% efi bzoj led

1079: [SCOI2008]著色方案

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 2133 Solved: 1287
[Submit][Status][Discuss]

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,想起了王八棋。
然後定狀態,很多維的話只能一種一維咯,因為要轉移所以還要加一維
f[a][b][c][d][e][k] 鉛絲維是種類最後是上一塊放的是第幾種
轉移略麻煩,比如這次三塊的減了一,兩塊的就加了一,乘的時候就要減回來。
乘法原理,自行體會,,,,,, 
*/ #include<iostream> #include<cstdio> #define ll long long #define mod 1000000007 using namespace std; ll f[16][16][16][16][16][6]; int x[6],n; bool L[16][16][16][16][16][6]; ll dp(int a,int b,int c,int d,int e,int k) { ll t=0; if(L[a][b][c][d][e][k])return f[a][b][c][d][e][k];
if(a+b+c+d+e==0)return 1; if(a) t+=(a-(k==2))*dp(a-1,b,c,d,e,1 ); if(b) t+=(b-(k==3))*dp(a+1,b-1,c,d,e,2); if(c) t+=(c-(k==4))*dp(a,b+1,c-1,d,e,3); if(d) t+=(d-(k==5))*dp(a,b,c+1,d-1,e,4); if(e) t+=e*dp(a,b,c,d+1,e-1,5); L[a][b][c][d][e][k]=1; return f[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); x[t]++; } printf("%lld",dp(x[1],x[2],x[3],x[4],x[5],0)); return 0; }

bzoj1079: [SCOI2008]著色方案(dp)