1 条题解

  • 0
    @ 2026-4-29 15:56:28

    一、题意回顾

    给定一个二进制字符串(仅包含 0011),你可以执行任意次如下操作:

    • 选择三个位置 i<j<ki<j<k,对这三个字符进行循环左移循环右移

    目标:把字符串变成有序形式(所有 00 在前,所有 11 在后)。 求最少操作次数


    二、终极结论(核心公式)

    答案=错位字符总数2\boldsymbol{答案 = \frac{错位字符总数}{2}}

    或者等价表述:

    答案=前缀中错误的1的数量答案 = 前缀中错误的 \boldsymbol{1} 的数量

    三、严格证明(官方标准推导)

    1. 有序串的结构

    设字符串中 00 的总数量为 c0\boldsymbol{c_0}。 排序后的字符串一定满足:

    • c0c_0 个字符全是 0\boldsymbol{0}
    • 后面的字符全是 1\boldsymbol{1}

    2. 定义错位字符

    • 错误的 11:出现在c0c_0中的 11
    • 错误的 00:出现在nc0n-c_0中的 00

    显然:

    错误1的数量=错误0的数量=M错误1的数量 = 错误0的数量 = M

    3. 一次操作能修复多少错误?

    一次操作可以恰好修复一组错位

    • 把一个错误的 11 变成 00
    • 把一个错误的 00 变成 11

    因此:

    最少操作次数=M最少操作次数 = M

    4. 为什么代码可以直接写 ans/2?

    错位字符总数 = 错误 11 数 + 错误 00 数 = 2M2M

    ans=2M    M=ans/2ans = 2M \implies M = ans/2

    四、标程代码逐行详解

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
     
    int main(){
        int tt;
        cin >> tt;          // 测试用例数
     
        while(tt--){
            int n;
            string s;
            cin >> n >> s;  // 输入字符串
     
            int ans = 0;
            string p = s;
            sort(p.begin(), p.end());  // 生成目标有序串
     
            // 统计所有错位的字符数量
            for(int i = 0; i < n; i++) 
                if(s[i] != p[i]) ans++;
     
            // 答案 = 错位总数 / 2
            cout << ans / 2 << '\n';
        }
        return 0;
    }
    

    五、代码执行逻辑(极简版)

    1. 把原字符串排序,得到目标串
    2. 逐位比较,统计有多少位不一样
    3. 答案就是 不同位数 ÷ 2

    六、样例演示

    输入:0110 排序后:0011 比较:

    0 1 1 0
    0 0 1 1
    ↑   ↑   ← 2 位不同
    

    答案:2/2=12/2 = 1,与样例输出一致。


    七、时间复杂度

    O(n)每组测试用例O(n) \quad \text{每组测试用例}

    完全满足题目限制。


    八、一句话记住解法

    统计错位字符数量,直接除以 2 就是答案。

    • 1

    信息

    ID
    6703
    时间
    1000ms
    内存
    256MiB
    难度
    1
    标签
    递交数
    0
    已通过
    0
    上传者