NC20273 [SCOI2009]粉刷匠

题目链接

题目

题目描述

windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。

windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。

如果windy只能粉刷 T 次,他最多能正确粉刷多少格子?

一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。

输入描述

输入文件paint.in第一行包含三个整数,N M T。
接下来有N行,每行一个长度为M的字符串,'0'表示红色,'1'表示蓝色。

输出描述

输出文件paint.out包含一个整数,最多能正确粉刷的格子数。

示例1

输入

3 6 3
111111
000000
001100

输出

16

备注

30%的数据,满足 1N,M10;0T100
100%的数据,满足 1N,M50;0T2500

题解

方法一

知识点:线性dp。

这道题相当于 k 串最大和套 k 串最大和,十分巧妙。

首先考虑设 f[i][j] 为考虑到第 i 行,共连续刷了 j 次的最多刷对格数。发现转移时的累加和变为第 i 行,考虑到第 m 格,共刷了 k 次的最多刷对格数,用 g[i][m][k] 表示。有转移方程为:

f[i][j]=max(f[i1][j],f[i1][jk]+g[i][m][k]),1kj

接下来考虑求 g[i][j][k] ,每行是独立的,第一维可以不考虑。接下来就和 k 串最大和一致,有转移方程:

g[i][j][k]=max(g[i][j1][k],g[i][jl][k1]+max(s,ls)),s=sum[i][j]sum[i][jl],1lj

其中 sum[i][j] 代表第 i 行前 j 个数里 1 的数量,max(s,ls) 表示新刷的 [jl+1,j] 里刷数量最多的种类。

时间复杂度 O(nm2t+nt2)

空间复杂度 O(nmt)

方法二

知识点:线性dp。

思路差不多,就是状态设置不一样,设 f[i][j][k][l] 表示为在 (i,j) 处的格子,已经刷了 k 次,这个格子状态为 l (0/1,涂0/涂1)。显然有转移方程:

{f[i][j][k][0]=max(f[i][j1][k1][0],f[i][j1][k1][1])+[a[i][j]=0],j=1f[i][j][k][1]=max(f[i][j1][k1][0],f[i][j1][k1][0])+[a[i][j]=1],j=1f[i][j][k][0]=max(f[i][j1][k][0],f[i][j1][k1][1])+[a[i][j]=0],j1f[i][j][k][1]=max(f[i][j1][k1][0],f[i][j1][k][0])+[a[i][j]=1],j1

j=1 ,必须换行,即必须分段。

时间复杂度 O(nmt)

空间复杂度 O(nmt)

代码

方法一

#include <bits/stdc++.h>
using namespace std;
int sum[57][57], f[57][2507], g[57][57][2507];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m, t;
cin >> n >> m >> t;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
char x;
cin >> x;
sum[i][j] = sum[i][j - 1];
if (x == '1') sum[i][j]++;
}
}
for (int i = 1;i <= n;i++)
for (int j = 1;j <= m;j++)
for (int k = 1;k <= t;k++)
for (int l = 1;l <= j;l++)
g[i][j][k] = max(g[i][j][k], g[i][j - l][k - 1] + max(sum[i][j] - sum[i][j - l], l - (sum[i][j] - sum[i][j - l])));
for (int i = 1;i <= n;i++)
for (int j = 1;j <= t;j++)
for (int k = 1;k <= j;k++)
f[i][j] = max(f[i][j], f[i - 1][j - k] + g[i][m][k]);
cout << f[n][t] << '\n';
return 0;
}

方法二

#include <bits/stdc++.h>
using namespace std;
int a[57][57], f[57][57][2507][2];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m, t;
cin >> n >> m >> t;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
char x;
cin >> x;
a[i][j] = x - '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) {
f[i][j][k][0] = max(f[i - 1][m][k - 1][1], f[i - 1][m][k - 1][0]) + (a[i][j] == 0);
f[i][j][k][1] = max(f[i - 1][m][k - 1][1], f[i - 1][m][k - 1][0]) + (a[i][j] == 1);
}
else {
f[i][j][k][0] = max(f[i][j - 1][k][0], f[i][j - 1][k - 1][1]) + (a[i][j] == 0);
f[i][j][k][1] = max(f[i][j - 1][k - 1][0], f[i][j - 1][k][1]) + (a[i][j] == 1);
}
}
}
}
cout << max(f[n][m][t][0], f[n][m][t][1]) << '\n';
return 0;
}
posted @   空白菌  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示