bzoj1079[SCOI2008]着色方案
题目链接
题解
状态设计好神呐
dp[a][b][c][d][e][last]
表示剩余1个的有a中,2个的有b中三个的有c中....
last表示上次转移的种类
然后记忆化搜索一下
乘法原理转移
代码
#include<cstdio>
#include<algorithm>
inline int read () {
int x = 0,f = 1;
char c = getchar();
while(c <= '0' || c > '9') {if(c == '-')f = -1;c = getchar();}
while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar();
return x * f;
}
#define LL long long
const int mod = 1e9 + 7;
const int maxn = 19;
LL dp[maxn][maxn][maxn][maxn][maxn][7];
LL dfs(int a,int b,int c,int d,int e,int last) { //last 安放改点的等价类与上次等价类变化后相同,减掉
if(!a && !b && !c && !d && !e) return 1;
if(dp[a][b][c][d][e][last]) return dp[a][b][c][d][e][last];
LL ret = 0;
if(a) ret +=dfs(a - 1,b,c,d,e,1) * (a - (last == 2)) ;
ret %= mod;
if(b) ret +=dfs(a + 1,b - 1,c,d,e,2) * (b - (last == 3)) ;
ret %= mod;
if(c) ret +=dfs(a ,b + 1,c - 1,d,e,3) * (c - (last == 4)) ;
ret %= mod;
if(d) ret +=dfs(a,b,c + 1,d - 1,e,4) * (d - (last == 5)) ;
ret %= mod;
if(e) ret +=dfs(a,b,c,d + 1,e - 1,5) * e ;// 上次等价类已经转移纸last - 1
ret %= mod;
return dp[a][b][c][d][e][last] = ret;
}
int C[maxn];
int main() {
int n = read();
for(int i = 1;i <= n ;++ i) C[read()] ++;
printf("%lld\n",dfs(C[1],C[2],C[3],C[4],C[5],0) % mod);
return 0;
}