[BZOJ1079][SCOI2008]着色方案
1079: [SCOI2008]着色方案
Time Limit: 10 Sec Memory Limit: 162 MB Submit: 2198 Solved: 1332 [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
1 2 3
Sample Output
10
HINT
100%的数据满足:1 <= k <= 15, 1 <= ci <= 5
可以发现数量相同的颜色其实是等价的
那么记录一下每种数量的颜色个数以及上一步选了什么颜色
加加乘乘即可
#pragma GCC optimize("O2") #include <cstdio> typedef long long ll; const int mod = 1000000007; inline void add(ll &x, const ll &y){ x = (x + y) % mod; } bool mark[16][16][16][16][16][6] = {false}; ll f[16][16][16][16][16][6]; ll dp(int x1, int x2, int x3, int x4, int x5, int k){ if(x1 + x2 + x3 + x4 + x5 == 0) return 1; if(mark[x1][x2][x3][x4][x5][k]) return f[x1][x2][x3][x4][x5][k]; ll &ans = f[x1][x2][x3][x4][x5][k]; if(x1) add(ans, (x1 - (k == 2)) * dp(x1 - 1, x2, x3, x4, x5, 1)); if(x2) add(ans, (x2 - (k == 3)) * dp(x1 + 1, x2 - 1, x3, x4, x5, 2)); if(x3) add(ans, (x3 - (k == 4)) * dp(x1, x2 + 1, x3 - 1, x4, x5, 3)); if(x4) add(ans, (x4 - (k == 5)) * dp(x1, x2, x3 + 1, x4 - 1, x5, 4)); if(x5) add(ans, x5 * dp(x1, x2, x3, x4 + 1, x5 -1, 5)); mark[x1][x2][x3][x4][x5][k] = true; return ans; } int main(){ int k, c[6] = {0}; scanf("%d", &k); for(int t, i = 1; i <= k; i++){ scanf("%d", &t); c[t]++; } printf("%lld\n", dp(c[1], c[2], c[3], c[4], c[5], 1)); return 0; }