*题解:P11218 【MX-S4-T2】「yyOI R2」youyou 不喜欢夏天

题目链接

解析

考虑应该交换哪些列,应该是那些只选了一个 \(1\),而另一个元素是 \(0\) 的列,此时交换操作可以使最终连通块 \(1\) 的个数 \(-1\),\(0\) 的个数 \(+1\),对答案做 \(-2\) 的贡献。假设我们选了 \(k\) 个这样的列,那么就做了 \(-2\min(k,m)\) 的贡献。

一个朴素的想法就是把 \(k\) 设到状态里,无法通过。事实上我们可以讨论最终 \(\min(k,m)\) 的取值,若 \(\min(k,m) = k\),那么可以直接把 \(k\) 在选取的过程中算进贡献里,就算选了超过 \(m\) 个,也必定更劣,因为减了 \(2k > 2m\),且此种情况会在后面被考虑。否则 \(\min(k,m) = m\),可以不管选了多少个这样的列,最后统一 \(-2m\),选不满 \(m\) 个同样说明更劣,且此种情况会在前面被考虑。两种情况取 \(\max\) 即可。

故设 \(f_{i,00/01/10/11}\) 表示考虑了前 \(i\) 列,延伸到第 \(i\) 列的连通块,前一列没有选 / 选了第一行 / 选了第二行 / 两行都选了的贡献。跑两次 DP 即可,转移方程见代码。

时间复杂度 \(O(n)\)。

没想到的地方

分类讨论 \(\min(k,m)\)。

总结

尝试将贡献写成表达式。

看到最值尝试分类讨论。

代码

#include<bits/stdc++.h>
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
const int N = 2e6 + 5;
int f[N][4];
int a1[N],a2[N];
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int c,T;
	cin>>c>>T;
	while(T--){
		int n,m;
		cin>>n>>m;
		string s1,s2;
		cin>>s1>>s2;
		s1 = " " + s1;
		s2 = " " + s2;
		for(int i=1;i<=n;i++){
			a1[i] = (s1[i] - '0') == 0 ? -1 : 1;
			a2[i] = (s2[i] - '0') == 0 ? -1 : 1;
		}
		int res = 0;
		for(int i=0;i<n;i++){
			f[i + 1][0] = 0;
			f[i + 1][1] = a1[i + 1] - 2 * (a1[i + 1] == 1 && a2[i + 1] == -1);
			f[i + 1][2] = a2[i + 1] - 2 * (a1[i + 1] == -1 && a2[i + 1] == 1);
			f[i + 1][3] = a1[i + 1] + a2[i + 1];
			for(int j=1;j<4;j++){
				if(j & 1){
					f[i + 1][1] = max(f[i + 1][1],f[i][j] + a1[i + 1] - 2 * (a1[i + 1] == 1 && a2[i + 1] == -1));
				}
				if(j & 2){
					f[i + 1][2] = max(f[i + 1][2],f[i][j] + a2[i + 1] - 2 * (a2[i + 1] == 1 && a1[i + 1] == -1));
				}
				f[i + 1][3] = max(f[i + 1][3],f[i][j] + a1[i + 1] + a2[i + 1]);
			}
			res = max({res,f[i + 1][0],f[i + 1][1],f[i + 1][2],f[i + 1][3]});
		}
		for(int i=0;i<n;i++){
			f[i + 1][0] = 0;
			f[i + 1][1] = a1[i + 1];
			f[i + 1][2] = a2[i + 1];
			f[i + 1][3] = a1[i + 1] + a2[i + 1];
			for(int j=1;j<4;j++){
				if(j & 1){
					f[i + 1][1] = max(f[i + 1][1],f[i][j] + a1[i + 1] );
				}
				if(j & 2){
					f[i + 1][2] = max(f[i + 1][2],f[i][j] + a2[i + 1]);
				}
				f[i + 1][3] = max(f[i + 1][3],f[i][j] + a1[i + 1] + a2[i + 1]);
			}
			res = max(res,max({f[i + 1][0],f[i + 1][1],f[i + 1][2],f[i + 1][3]}) - 2 * m);
		}
		cout<<res<<'\n';
	}
	return 0;
}
posted @ 2026-10-14 17:52  yutar  阅读(8)  评论(0)    收藏  举报