[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

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
", dp(c[1], c[2], c[3], c[4], c[5], 1));
    return 0;
}
原文地址:https://www.cnblogs.com/ruoruoruo/p/7633007.html