有n个木块排成一行,从左到右依次编号为1~n。你有k种颜色的油漆,其中第i 种颜色的油漆足够涂ci 个木块。所有油漆刚好足够涂满所有木块,即 c1+c2+...+ck=n。相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案。
Input
第一行为一个正整数k,第二行包含k个整数c1, c2, ... , ck。
Output
输出一个整数,即方案总数模1,000,000,007的结果。
Sample Input
样例1:
3
1 2 3
样例2:
5
2 2 2 2 2
样例3:
10
1 1 2 2 3 3 4 4 5 5
题解:
这个题目我们可以试着用记忆化搜索,状态设置的十分巧妙,首先我们可以看到ci是小于等于5的吧,并且只要数量一样,
那么颜色对答案的贡献其实就是一样的,所有’我们可以定义一个五维的数组F[a1][a2][a3][a4][a5][h]表示数量为1的颜料数是
a1,数量为2的颜色的颜色数为a2.......的最大方案数,然后转移的话看我代码吧,转移时要注意,最后一位是存上一次决策,
如果上个决策是用剩余数为4的颜色,那么显然剩余数为3的颜色有一种是从4转移的,此时再用这种颜色就会染上相同的颜色。
注意一下就好了。
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<cstring> #define ll long long const int MOD=1000000007; using namespace std; int num[6]; ll f[16][16][16][16][16][6]; ll dp(int a1,int a2,int a3,int a4,int a5,int last){ ll now=0; if((a1 | a2 | a3 | a4 | a5)==0) return f[a1][a2][a3][a4][a5][last]=1; if(f[a1][a2][a3][a4][a5][last]) return f[a1][a2][a3][a4][a5][last]; if(a1) now+=(a1-(last==2))*dp(a1-1,a2,a3,a4,a5,1);now%=MOD; if(a2) now+=(a2-(last==3))*dp(a1+1,a2-1,a3,a4,a5,2);now%=MOD; if(a3) now+=(a3-(last==4))*dp(a1,a2+1,a3-1,a4,a5,3);now%=MOD; if(a4) now+=(a4-(last==5))*dp(a1,a2,a3+1,a4-1,a5,4);now%=MOD; if(a5) now+=a5*dp(a1,a2,a3,a4+1,a5-1,5);now%=MOD; f[a1][a2][a3][a4][a5][last]=now;now%=MOD; return now; } int main(){ int n; memset(f,0,sizeof(f)); scanf("%d",&n); for(int i=1;i<=n;i++){int x;scanf("%d",&x);num[x]++;} printf("%lld",dp(num[1],num[2],num[3],num[4],num[5],0)); return 0; }