bzoj1079[SCOI2008]着色方案

题目链接

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;
}
posted @ 2018-04-17 20:48  zzzzx  阅读(...)  评论(... 编辑 收藏