[luoguP11361/NOIP2024] 编辑字符串
题意
给出两个 0/1 字符串,每个字符串有一些位置被标记,无法交换。求通过任意多次的交换相邻元素操作能够使两个字符串最多多少位置相同。
sol
一道贪心题。
显然交换相邻的操作可以使该字符串可以交换的一段任意排列。由于不同位置的贡献最大只为 ,因此在任何位置贡献都没有区别,考虑将贡献的位置尽可能向左靠拢。将两个字符串按照无法交换的位置分段,当遇到某两段的分界点时,如果是两个字符串的分界点则计算分界点左侧能够匹配的数量,公式为 ;如果是一个字符串的分界点,则使用另一侧的分界点尽可能地匹配,注意最右端的边界也需要作为分界点处理。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100005;
char s1[N], s2[N], t1[N], t2[N];
int T, n;
int cnt10[N], cnt11[N], rb1[N];
int cnt20[N], cnt21[N], rb2[N];
int main(){
// freopen("edit2.in", "r", stdin);
scanf("%d", &T);
while (T -- ){
scanf("%d%s%s%s%s", &n, s1 + 1, s2 + 1, t1 + 1, t2 + 1);
for (int i = 1; i <= n; i ++ ) {
cnt10[i] = cnt10[i - 1], cnt11[i] = cnt11[i - 1];
cnt20[i] = cnt20[i - 1], cnt21[i] = cnt21[i - 1];
if (s1[i] == '1') cnt11[i] ++ ;
else cnt10[i] ++ ;
if (s2[i] == '1') cnt21[i] ++ ;
else cnt20[i] ++ ;
}
rb1[n + 1] = rb2[n + 1] = n;
for (int i = n; i; i -- ){
if (t1[i] == '1') rb1[i] = rb1[i + 1];
else rb1[i] = i - 1;
if (t2[i] == '1') rb2[i] = rb2[i + 1];
else rb2[i] = i - 1;
}
int left0 = 0, left1 = 0, state = -1, ans = 0;
int last = 0;
for (int i = 1; i <= n + 1; i ++ ) {
if (i <= n && t1[i] == '1' && t2[i] == '1') continue;
if (t1[i] == '1') {
int need0 = cnt20[i - 1] - cnt20[last], need1 = cnt21[i - 1] - cnt21[last];
if (state == 2) need0 = min(left0, i - last - 1), need1 = min(left1, i - last - 1);
if (state != 1) left0 = cnt10[rb1[i]] - cnt10[last], left1 = cnt11[rb1[i]] - cnt11[last];
int prov0 = min(need0, left0), prov1 = min(need1, left1);
ans += prov0 + prov1;
left0 -= prov0, left1 -= prov1;
if (s2[i] == '0' && left0) ans ++ , left0 -- ;
if (s2[i] == '1' && left1) ans ++ , left1 -- ;
state = 1;
}
else if (t2[i] == '1') {
int need0 = cnt10[i - 1] - cnt10[last], need1 = cnt11[i - 1] - cnt11[last];
if (state == 1) need0 = min(left0, i - last - 1), need1 = min(left1, i - last - 1);
if (state != 2) left0 = cnt20[rb2[i]] - cnt20[last], left1 = cnt21[rb2[i]] - cnt21[last];
int prov0 = min(need0, left0), prov1 = min(need1, left1);
ans += prov0 + prov1;
left0 -= prov0, left1 -= prov1;
if (s1[i] == '0' && left0) ans ++ , left0 -- ;
if (s1[i] == '1' && left1) ans ++ , left1 -- ;
state = 2;
}
else {
int need10 = cnt10[i - 1] - cnt10[last], need11 = cnt11[i - 1] - cnt11[last];
int need20 = cnt20[i - 1] - cnt20[last], need21 = cnt21[i - 1] - cnt21[last];
if (state == 1) need10 = min(left0, i - last - 1), need11 = min(left1, i - last - 1);
if (state == 2) need20 = min(left0, i - last - 1), need21 = min(left1, i - last - 1);
ans += min(need10, need20) + min(need11, need21);
if (s1[i] == s2[i]) ans ++ ;
left0 = left1 = 0;
state = -1;
}
last = i;
}
printf("%d\n", ans - 1);
}
return 0;
}
分类:
题解 / 2024训练
标签:
基础算法
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战