首先预处理出
sum0[i][j]
和
sum1[i][j]
,分别表示第
i
行的前
进行第一次DP,
f[i][j][k]
表示第
i
行到了第
转移就是,如果
(i,j)
被粉刷到,那么就枚举第
k
次粉刷的开始位置;如果
f[i][l][k−1]+sum0[i][j]−sum0[i][l],
f[i][l][k−1]+sum1[i][j]−sum1[i][l]))
然后再进行第二次DP,
g[i][j]
表示到了第
i
行粉刷了
g[i][j]=maxmin(m,j)k=0(g[i−1][j−k]+f[i][m][k])
。
最后答案就是
g[n][T]
。复杂度
O(nm3+nmT)
。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 55, M = 3005;
int n, m, T, a[N][N], f[N][N][N], g[N][M], sum[N][N][2];
void chkmax(int &a, int b) {if (b > a) a = b;}
int main() {
int i, j, k, l; scanf("%d%d%d", &n, &m, &T);
for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) {
scanf("%1d", &a[i][j]);
sum[i][j][a[i][j]] = sum[i][j - 1][a[i][j]] + 1;
sum[i][j][a[i][j] ^ 1] = sum[i][j - 1][a[i][j] ^ 1];
}
for (i = 1; i <= n; i++) for (j = 1; j <= m; j++)
for (k = 1; k <= m; k++) for (l = 0; l < j; l++) {
chkmax(f[i][j][k], f[i][l][k]);
chkmax(f[i][j][k], f[i][l][k - 1] + sum[i][j][0] - sum[i][l][0]);
chkmax(f[i][j][k], f[i][l][k - 1] + sum[i][j][1] - sum[i][l][1]);
}
for (i = 1; i <= n; i++) for (j = 1; j <= T; j++)
for (k = 0; k <= min(m, j); k++)
chkmax(g[i][j], g[i - 1][j - k] + f[i][m][k]);
cout << g[n][T] << endl;
return 0;
}