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
1 2 3
Sample Output
10
HINT
100%的数据满足:1 <= k <= 15, 1 <= ci <= 5
记忆化搜索一下吧。。。也算是DP吧。。。因为每种颜色最多5个。。所以表示有a个1个的,b个2个的,c个3个的,d个4个的,e个5个的,前一个是f个的,的方案总数。。。
然后转移就比较显然了。。。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<queue> 10 #include<vector> 11 #include<set> 12 #define inf 1000000000 13 #define maxn 16 14 #define maxm 6 15 #define eps 1e-10 16 #define ll long long 17 #define mod 1000000007 18 #define for0(i,n) for(int i=0;i<=(n);i++) 19 #define for1(i,n) for(int i=1;i<=(n);i++) 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 21 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 22 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 23 using namespace std; 24 int read(){ 25 int x=0,f=1;char ch=getchar(); 26 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 27 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 28 return x*f; 29 } 30 ll F[maxn][maxn][maxn][maxn][maxn][maxn]; 31 int k,w[maxn],t[maxn]; 32 ll dfs(int a,int b,int c,int d,int e,int f){ 33 if(F[a][b][c][d][e][f])return F[a][b][c][d][e][f]; 34 if(a+b+c+d+e==0)return 1; 35 if(a)F[a][b][c][d][e][f]+=((a-(f==2))*dfs(a-1,b,c,d,e,1)%mod); 36 if(b)F[a][b][c][d][e][f]+=((b-(f==3))*dfs(a+1,b-1,c,d,e,2)%mod); 37 if(c)F[a][b][c][d][e][f]+=((c-(f==4))*dfs(a,b+1,c-1,d,e,3)%mod); 38 if(d)F[a][b][c][d][e][f]+=((d-(f==5))*dfs(a,b,c+1,d-1,e,4)%mod); 39 if(e)F[a][b][c][d][e][f]+=((e*dfs(a,b,c,d+1,e-1,5))%mod); 40 return F[a][b][c][d][e][f]%mod; 41 } 42 int main(){ 43 //freopen("input.txt","r",stdin); 44 //freopen("output.txt","w",stdout); 45 k=read(); 46 for1(i,k) 47 w[i]=read(),t[w[i]]++; 48 printf("%lld",dfs(t[1],t[2],t[3],t[4],t[5],0)); 49 return 0; 50 }