P11361 [NOIP2024] 编辑字符串

原题链接

算法

贪心, 模拟.

思路

特殊性质 A

因为 \(s_1\) 字符串内的字符都相同, 所以无论 \(s_2\) 中怎么排, 最大的匹配数都是不变的.

特殊性质 B

\(t_1 = t_2\), 也就是两字符串能够交换的位置相同, 而每一段只能在内部交换, 也就是每一个 \(t_i=0\) 相当于一个节点, 每两个节点中可以任意交换, 这样特殊性质 B 就好做了.
考虑贪心, 答案即为每一段中 0 的数量的最小值加上 1 的数量的最小值.

根据特殊性质 B, 我们可以知道原字符串可以当过多个字符串拼接起来, 每一个 \(t_i=0\) 便是一个节点.
从左往右扫过去, 每个位置我们可以分三种情况进行讨论:

    1. 该位置两字符串都可以交换.
      因为当前不能确定这该段字符串 0 和 1 的数量, 所以我们可以先将其存下, 放在结尾再进行操作.
    1. 该位置两字符串都不能进行交换.
      同特殊性质 B, 我们直接将答案加上 0 的数量的最小值加上 1 的数量的最小值即可, 最后记得清零.
    1. 该位置一个可换, 一个不可换.
      我们进行贪心.
      对于不可换的一个字符串, 这就相当于是一个节点了, 所以之前统计的 0 1 数量需要清零.
      对于可换的字符串, 我们可以优先将其对这一位进行匹配了, 因为你匹配了这一位一定是不劣的.
#include "iostream"
#include "string"

using namespace std;

int n;
string s1, s2, f1, f2;

void init()
{
    cin >> n;
    cin >> s1 >> s2;
    cin >> f1 >> f2;
    return;
}

void calculate()
{

    int idx = 0, i = 0, j = 0, ans = 0;
    int cnt1[2], cnt2[2];

    cnt1[0] = cnt1[1] = cnt2[0] = cnt2[1] = 0;

    while (idx ^ n)
    {
        while (f1[i] == '1' and i ^ n)
            ++cnt1[s1[i] - '0'], ++i;
        while (f2[j] == '1' and j ^ n)
            ++cnt2[s2[j] - '0'], ++j;

        while (idx ^ i and idx ^ j)
        {
            if (cnt1[0] and cnt2[0])
            {
                --cnt1[0], --cnt2[0];
                ++ans;
            }
            else if (cnt1[1] and cnt2[1])
            {
                --cnt1[1], --cnt2[1];
                ++ans;
            }
            ++idx;
        }
        if (idx == n)
            break;
        if (i == j)
        {
            ans += (s1[i] == s2[j]);
            cnt1[0] = cnt1[1] = cnt2[0] = cnt2[1] = 0;
            ++i, ++j;
        }
        else if (i > j)
        {
            if (cnt1[s2[j] - '0'])
            {
                --cnt1[s2[j] - '0'];
                ++ans;
            }
            cnt2[0] = cnt2[1] = 0;
            ++j;
        }
        else
        {
            if (cnt2[s1[i] - '0'])
            {
                --cnt2[s1[i] - '0'];
                ++ans;
            }
            cnt1[0] = cnt1[1] = 0;
            ++i;
        }
        ++idx;
    }

    cout << ans << '\n';
    return;
}

void solve()
{
    init();
    calculate();
    return;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T;
    cin >> T;
    while (T--)
        solve();
    return 0;
}
posted @   Steven1013  阅读(5)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示