N 條木板,每條 M 格。每格目標顏色為紅(0)或藍(1)。每次操作:選一條木板上連續段塗單一顏色。每格最多塗一次。共 T 次操作機會。求最多正確塗色格數(未塗或顏色錯誤均視為錯誤)。
資料範圍:N,M ≤ 50, T ≤ 2500。
木板間無相互影響,可獨立計算。對單木板,定義 f[j][k]:前 j 格使用 k 次操作,最多正確塗色格數。
前綴和 sum[j]:前 j 格中目標為藍(1)的格數。區間 [l+1, j] 塗藍正確數 = sum[j]-sum[l];塗紅正確數 = (j-l) - (sum[j]-sum[l])。取較大者。
轉移:
f[j][k] = max_{0≤l
l,新段為 [l+1, j]。f[0][0]=0,其餘 -inf。O(M^3),M≤50 可接受。計算出每木板 board[i][k] = f[M][k]:第 i 木板用 k 次操作的最大正確數。
定義 g[i][j]:前 i 條木板共用 j 次操作的最大正確總數。
轉移:
g[i][j] = max_{0≤k≤min(j,M)} { g[i-1][j-k] + board[i][k] }
i 木板分配 k 次操作。g[0][0]=0。O(N * T * M) ≈ 50 × 2500 × 50 = 6.25e6,可接受。答案:max_{0≤j≤T} g[N][j]。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define F(i,j,n) for(int i=j;i<=n;i++)
int n, m, t, ans = 0;
int sum[55], f[55][55], g[55][2505];
char s[55];
inline int read() {
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x*10 + ch - '0'; ch = getchar(); }
return x * f;
}
int main() {
n = read(); m = read(); t = read();
F(i, 1, n) {
scanf("%s", s+1);
F(j, 1, m) sum[j] = sum[j-1] + (s[j] == '1');
F(k, 1, m) F(j, 1, m) {
f[j][k] = 0;
F(l, 0, j-1) {
int tmp = sum[j] - sum[l];
f[j][k] = max(f[j][k], f[l][k-1] + max(tmp, j-l-tmp));
}
}
F(j, 1, t) F(k, 1, min(j, m))
g[i][j] = max(g[i][j], g[i-1][j-k] + f[m][k]);
}
F(i, 1, t) ans = max(ans, g[n][i]);
printf("%d\n", ans);
return 0;
}
O(1) 計算區間正確數。-inf(靜態陣列預設 0,題目保證正確數非負)。read() 加速。