其他分享
首页 > 其他分享> > [luogu2476][bzoj1079][SCOI2008]着色方案

[luogu2476][bzoj1079][SCOI2008]着色方案

作者:互联网

题目描述

有n个木块排成一行,从左到右依次编号为1~n。你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块。所有油漆刚好足够涂满所有木块,即c1+c2+…+ck=n。相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的着色方案。

分析

很多网上的题解都讲的不怎么清楚,我将个人思考到一发WAAC的过程清楚地讲一遍。
首先考虑如何定义状态,一眼就发现了\(c_i<=5\),说明什么,我们可以直接将各个颜色还剩下多少的个数都压到状态中,也就是一个五维的状态。而且题目很明显的发现如果定义各个颜色还有多少个,那么需要用15维,数组直接爆炸。
但是题目要求不能相邻,因为我们已经采取了用个数作为前面的5个状态,那么参考chess的思路,排列组合来排除是否是相邻的,这个待会再说。说的明白一点,就是在定义\(1\)维状态,表示上一个格子我们用的是个数是\(lst\)颜色。
总结一下:\(f[i1][i2][i3][i4][i5][lst]\),\(i_i\)表示的是\(i\)颜色还有\(i_i\)个,前一个涂得颜色是\(lst\)个颜色时方案总数。

我们把这个放棋子的过程,按照从左到右的顺序。


接下来我们思考决策。我们举3个例子,分别是我们放的颜色是\(1\)和\(3\)和\(5\)。
如果我们当前放的颜色是个数为\(1\)的,那么分成两种情况:

总结一下转移方程
\[if (lst=2) f[i1][i2][i3][i4][i5][lst] += (i1 - 1) * f[i1-1][i2][i3][i4][i5][1]\]
否则
\[f[i1][i2][i3][i4][i5][lst] += i1*f[i1-1][i2][i3][i4][i5][1]\]


如果我们放的颜色个数为\(3\),这种情况和\(2\)以及\(4\)是相同的,以3为例:

总结一下转移方程
\[if (lst=4) f[i1][i2][i3][i4][i5][lst]+=(i3-1)*f[i1][i2+1][i3-1][i4][i5][3]\]
否则
\[f[i1][i2][i3][i4][i5][lst]+=i3*f[i1][i2+1][i3-1][i4][i5][3]\]


如果我们放的个数是\(5\):
因为不可能有颜色可以放了之后还有\(5\)个,那么就直接乘法原理就可以的到房成了。
总结一下转移方程
\[f[i1][i2][i3][i4][i5][lst] += i5*f[i1-1][i2][i3][i4][i5][5]\]

这道题目线性推常数较大,就采用了记忆化搜索来实现DP。

#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000000007
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') fl = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x *= fl;
}
ll f[16][16][16][16][16][6];
int d[6];
int n;
ll dfs(int i1, int i2, int i3, int i4, int i5, int lst) {
    if (f[i1][i2][i3][i4][i5][lst]) return f[i1][i2][i3][i4][i5][lst];
    ll res = 0;
    if (i1 > 0) {
        if (lst == 2) res = (res + (i1 - 1) * dfs(i1 - 1, i2, i3, i4, i5, 1)) % mod;
        else res = (res + i1 * dfs(i1 - 1, i2, i3, i4, i5, 1)) % mod;
    }
    if (i2 > 0) {
        if (lst == 3) res = (res + (i2 - 1) * dfs(i1 + 1, i2 - 1, i3, i4, i5, 2)) % mod;
        else res = (res + i2 * dfs(i1 + 1, i2 - 1, i3, i4, i5, 2)) % mod;
    }
    if (i3 > 0) {
        if (lst == 4) res = (res + (i3 - 1) * dfs(i1, i2 + 1, i3 - 1, i4, i5, 3)) % mod;
        else res = (res + i3 * dfs(i1, i2 + 1, i3 - 1, i4, i5, 3)) % mod;
    }
    if (i4 > 0) {
        if (lst == 5) res = (res + (i4 - 1) * dfs(i1, i2, i3 + 1, i4 - 1, i5, 4)) % mod;
        else res = (res + i4 * dfs(i1, i2, i3 + 1, i4 - 1, i5, 4)) % mod;
    }
    if (i5 > 0) {
        res = (res + i5 * dfs(i1, i2, i3, i4 + 1, i5 - 1, 5)) % mod;
    }
    return f[i1][i2][i3][i4][i5][lst] = res % mod;
}
int main() {
    int k;
    read(k);
    for (int i = 1; i <= k; i ++) {
        int x; 
        read(x);
        d[x] ++;
    }
    for (int i = 1; i <= 5; i ++) f[0][0][0][0][0][i] = 1;
    printf("%lld\n", dfs(d[1], d[2], d[3], d[4], d[5], 0) % mod);
    return 0;
}

标签:luogu2476,bzoj1079,i1,res,i3,i2,i5,i4,SCOI2008
来源: https://www.cnblogs.com/chhokmah/p/10562914.html