SCOI2009 粉刷匠

题目传送门


目前(2019-6-12)Luogu上第一篇题解是错误的,但是能(A) link
(hack)数据来自洛谷讨论

它的(DP)方式是设f[i][j][k][0/1]表示涂了(k)次,当前涂到了((i,j))这个点,这个点有没有涂对((0/1))

第一篇题解基本上是正确的(在我看来),但其中的一个小错误是,它强制当前行只能由上一行转移过来,而忽略了某些行其实可以不涂的条件
所以在转移当前行时应该将它之前的行都枚举一遍,选最优的转移

这样的时间复杂度会变高,理论上应该会TLE,但实际上跑的还是挺快的(数据太水)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
LL read() {
    LL k = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
        k = k * 10 + c - 48, c = getchar();
    return k * f;
}
char read_c() {
    char c = getchar();
    while(c != '1' && c != '0') c = getchar();
    return c - 48;
}
bool mat[55][55];
int f[55][55][2510][2];
int main() {
    int n = read(), m = read(), t = read();
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            mat[i][j] = read_c();
    int ans = 0;
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j)
            for(int k = 1; k <= t; ++k) {
                if(j == 1) {
                    for(int o = 1; o <= i; ++o)
                        f[i][j][k][0] = max(f[i][j][k][0], max(f[i-o][m][k-1][0], f[i-o][m][k-1][1])),
                        f[i][j][k][1] = max(f[i][j][k][1], max(f[i-o][m][k-1][1], f[i-o][m][k-1][0]) + 1);
                }
                else if(mat[i][j] == mat[i][j-1])
                    f[i][j][k][1] = max(f[i][j-1][k][1], f[i][j-1][k-1][0]) + 1,
                    f[i][j][k][0] = max(f[i][j-1][k][0], f[i][j-1][k-1][1]);
                else
                    f[i][j][k][1] = max(f[i][j-1][k][0], f[i][j-1][k-1][1]) + 1,
                    f[i][j][k][0] = max(f[i][j-1][k-1][0], f[i][j-1][k][1]);
                ans = max(ans, max(f[i][j][k][0], f[i][j][k][1]));
            }
    cout << ans;
    return 0;
}
原文地址:https://www.cnblogs.com/morslin/p/11855355.html