题解:P11361 [NOIP2024] 编辑字符串
已严肃开坑真题题解合集,主要解决自己总是写完一题过一段时间又不会了的问题。
当时考这个的时候学 OI 的时间还没有我上高中以来放过的假多,不过好在没有爆零,共计得分 35pts,但是所有的分数都是这道题贡献的,就差 T3 的 5pts 省三有了。
笑点解析:重写这道题还读错题了,挠头 1h + 看了 1.5h 题解才发现这个问题,令人忍俊不禁。
不说废话了我们开始介绍解法。
思路
注意到只有相邻的字符串才能进行交换,于是想到将字符串分段考虑。
我们按照字符是否能参与交换进行分段。在每一段里的数字是可以随便用的,我们利用前缀和计算出每一段的数字出现次数,接下来考虑怎么统计答案。
按照我们的处理方式,在都可以操作的情况下,如果两个字符串的同一个位置的字符各自所处的段里都有 0 或都有 1,那么该位置一定可以通过交换使得它们的字符相同,我们将其计入答案并将对应的数字在段内的出现次数减掉防止重复统计。
然后你可能会有疑惑,对于两个都不能交换或有一个不能交换的情况怎么办?回忆我们的分段方式好像确实没有考虑这一点,但是我们注意到如果字符不能交换,说明它是固定的和周围字符没关系,自然不能用人家的统计结果,我们就单独给它分出一段,再按照上面的方法求解即可。
代码
// 妈的写了一年才发现我读错题了
#include <bits/stdc++.h>
using namespace std;
const int MN = 1e5 + 3;
int n, s[MN][2], t[MN][2], ans, p[MN][2], sum1[MN][2], sum2[MN][2];
void get_in();
inline void fir() {
ans = 0;
get_in();
}
void solve() {
cin >> n;
fir();
for (int i = 1; i <= n; i++) {
p[i][0] = p[i - 1][0] + (!t[i][0] || !t[i - 1][0]);
sum1[p[i][0]][0] += (s[i][0] == 0);
sum1[p[i][0]][1] += (s[i][0] == 1);
p[i][1] = p[i - 1][1] + (!t[i][1] || !t[i - 1][1]);
sum2[p[i][1]][0] += (s[i][1] == 0);
sum2[p[i][1]][1] += (s[i][1] == 1);
}
for (int i = 1; i <= n; i++) {
if (sum1[p[i][0]][0] && sum2[p[i][1]][0]) {
ans++;
sum1[p[i][0]][0]--, sum2[p[i][1]][0]--;
continue;
}
else if (sum1[p[i][0]][1] && sum2[p[i][1]][1]) {
ans++;
sum1[p[i][0]][1]--, sum2[p[i][1]][1]--;
continue;
}
if (sum1[p[i][0]][0]) sum1[p[i][0]][0]--, sum2[p[i][1]][1]--;
else sum1[p[i][0]][1]--, sum2[p[i][1]][0]--;
}
cout << ans << "\n";
}
void get_in() {
char c;
for (int i = 1; i <= n; i++) {
cin >> c;
s[i][0] = c - '0';
}
for (int i = 1; i <= n; i++) {
cin >> c;
s[i][1] = c - '0';
}
for (int i = 1; i <= n; i++) {
cin >> c;
t[i][0] = c - '0';
}
for (int i = 1; i <= n; i++) {
cin >> c;
t[i][1] = c - '0';
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) solve();
return 0;
}
碎碎念
虽然洛谷上这个题是蓝 T2 是绿,但是我个人认为这个题是比下一题简单的(因为我下一道题不会),当然我也对这个难度评级没意见,毕竟每个人和每个人体感上是不一样的,加上这个题本身就看人。但是我说这些是因为今年 CSP-S 太难了感觉真和这次 NOIP 差不多。(不要骂我口牙我承认我是彩笔)

浙公网安备 33010602011771号