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
这题是真的苟谁第一感觉是6维DP
这一眼DP题,不是很会做,15^5随便艹
其实这道题不同颜色是没有顺序区分的,根据数据范围大胆猜测
f[a][b][c][d][e]表示还能涂1次的有a种,涂2次有b种,以此类推。。
然后避免重复多开一维last表示上一次用的是能涂几次的,转移是在不会就看代码吧。。
代码如下:
//MT_LI #include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; typedef long long ll; int s[6],n; ll mod=1000000007ll; ll f[17][17][17][17][17][6]; bool bk[17][17][17][17][17][6]; ll dp(int a,int b,int c,int d,int e,int last) { if((a|b|c|d|e)==0)return 1; if(bk[a][b][c][d][e][last])return f[a][b][c][d][e][last]; ll sum=0; if(a)sum+=(a-(last==2))*dp(a-1,b,c,d,e,1); if(b)sum+=(b-(last==3))*dp(a+1,b-1,c,d,e,2); if(c)sum+=(c-(last==4))*dp(a,b+1,c-1,d,e,3); if(d)sum+=(d-(last==5))*dp(a,b,c+1,d-1,e,4); if(e)sum+=e*dp(a,b,c,d+1,e-1,5); bk[a][b][c][d][e][last]=true; return f[a][b][c][d][e][last]=(sum%mod); } int main() { scanf("%d",&n); memset(bk,false,sizeof(bk)); memset(s,0,sizeof(s)); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); s[x]++; } printf("%lld ",dp(s[1],s[2],s[3],s[4],s[5],0)); return 0; }