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%的数据,满足 。
100%的数据,满足 。
题解
方法一
知识点:线性dp。
这道题相当于 串最大和套 串最大和,十分巧妙。
首先考虑设 为考虑到第 行,共连续刷了 次的最多刷对格数。发现转移时的累加和变为第 行,考虑到第 格,共刷了 次的最多刷对格数,用 表示。有转移方程为:
接下来考虑求 ,每行是独立的,第一维可以不考虑。接下来就和 串最大和一致,有转移方程:
其中 代表第 行前 个数里 的数量, 表示新刷的 里刷数量最多的种类。
时间复杂度
空间复杂度
方法二
知识点:线性dp。
思路差不多,就是状态设置不一样,设 表示为在 处的格子,已经刷了 次,这个格子状态为 (0/1,涂0/涂1)。显然有转移方程:
,必须换行,即必须分段。
时间复杂度
空间复杂度
代码
方法一
#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; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16580694.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧