【BZOJ1079】着色方案
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1079
吼题啊!
自己做,不会做,看完题解分析,不会写代码,看完代码自己写,交上去报错,复制题解代码交上去,通过。
类似于中国象棋,这道题也涉及合并本质相同的状态。最简单的思路是,设dp[a1][a2]...[ak][last]表示第几种颜色还剩几次可以使用,上一次用的是什么颜色的方案数。显然会炸,实际上,我们只关心还可以用几次的颜色有几种,并不关心具体是哪种颜色,刚好,每种颜色可以使用的次数并不多。设dp[a][b][c][d][e][l]表示还可用1次的颜色有a种,2次的有b种,...,上一次用的是剩余l次的颜色,注意是上一次用之前剩l次,对于当前是剩l-1次的某种颜色。然后讨论接下来选择剩几次的颜色即可,注意剩l+1次的颜色会少一种选择。
1 #include <cstdio> 2 #include <cstring> 3 4 typedef long long ll; 5 6 const int maxk = 16, maxc = 6, mod = 1e9 + 7; 7 8 int rest[maxc]; 9 ll dp[maxk][maxk][maxk][maxk][maxk][maxc]; 10 11 ll dfs(int a, int b, int c, int d, int e, int l) { 12 ll& f = dp[a][b][c][d][e][l]; 13 if (f != -1) return f; 14 if (a + b + c + d + e == 0) return 1; 15 ll t = 0; 16 if (a) t += (a - (l == 2)) * dfs(a - 1, b, c, d, e, 1); 17 if (b) t += (b - (l == 3)) * dfs(a + 1, b - 1, c, d, e, 2); 18 if (c) t += (c - (l == 4)) * dfs(a, b + 1, c - 1, d, e, 3); 19 if (d) t += (d - (l == 5)) * dfs(a, b, c + 1, d - 1, e, 4); 20 if (e) t += e * dfs(a, b, c, d + 1, e - 1, 5); 21 return f = t % mod; 22 } 23 24 int main() { 25 int k, c; 26 scanf("%d", &k); 27 for (int i = 1; i <= k; ++i) { 28 scanf("%d", &c); 29 ++rest[c]; 30 } 31 memset(dp, -1, sizeof(dp)); 32 printf("%lld", dfs(rest[1], rest[2], rest[3], rest[4], rest[5], 0)); 33 return 0; 34 }