1 条题解

  • 0
    @ 2026-5-14 20:20:18

    好的,根据你给出的代码,下面是详细的题解。


    题意简述

    nn 个花盆排成一行,字符串 sssi=1s_i = 1 表示有花(不可放兔子),si=0s_i = 0 表示空(必须放一只兔子)。
    每只兔子可以选择向左或向右看,但如果它看向的下一个花盆里有兔子,或者另一只兔子正从对面看过来(即两只兔子准备交换位置),则它们都不会跳。

    目标是判断是否存在一种方向安排,使得最终没有兔子实际发生跳跃


    问题转化

    • 花盆里如果有花(si=1s_i = 1),没有兔子,可以看作“墙”。
    • 空花盆(si=0s_i = 0)里都有兔子。
    • 兔子不跳的条件:
      对任意相邻的两个空花盆 iii+1i+1,不能出现 ii 向右看且 i+1i+1 向左看的情况(因为那样它们会互相跳向对方的位置)。
      同时,也不能出现某个兔子看向一个已经有兔子的位置(即看向相邻但非空的另一侧时,如果那边也有兔子且方向是朝这里,就会冲突)。

    实际上,经过分析(可参考官方题解或已知结论),这个问题的核心简化是:

    在一个连续的“空花盆段”中,如果它的长度是奇数,且两端都不是边界(即两端都被花包围),则无解。

    为什么?因为:

    • 在连续的空花盆段中,兔子必须安排方向使得不会产生相向而行。
    • 长度为 LL 的连续空位,必须像 RRR...LLLRRR...LLL 这样安排,中间有一个“分界点”,左边全向右,右边全向左。
    • 如果 LL 是偶数,可以平分,左右各 L/2L/2
    • 如果 LL 是奇数,则必须有一边的兔子比另一边多 11,那么多出的那只兔子如果看向段外,但段外是花(墙),则它看向墙就不会跳,这样是可以的。但如果段的两端都被花包围,那么两端兔子看向墙,中间必须有一个“中心兔子”向某个方向,但这会导致对面方向的兔子与它相向。经过分析(与代码对应),此时无解。

    代码逻辑对应

    代码中将原问题转化为对连续空段的奇偶性判断,并结合段是否被花包围来判定。

    代码中:

    • curr 表示当前是否处于一个被 11 包围的段(即左右都是 11 的段)?其实更准确地说,curr 标记的是上一个遇到的 11 是否与当前段构成“两端有 11”的情况
    • cnt 记录当前连续 00 的长度
    • 遍历时:
      • 遇到 s[i]=0s[i] = 0cnt++
      • 遇到 s[i]=s[i1]=0s[i] = s[i-1] = 0,说明连续 00 在继续
      • 遇到 s[i]=s[i1]=1s[i] = s[i-1] = 1,说明两个 11 之间夹了一段 00,此时:
        • 如果 curr 为真(表示上一段的左边是 11,即这一段 00 左右都是 11
        • cnt 是奇数
        • 则无解(ok = false
        • 然后重置 curr = true(新段左边也是 11?其实这里是标记下一个段也是被 11 包围)
      • 最后,遍历结束后,如果最后一段 00 也是被 11 包围(curr 真)且长度是奇数,也无解。

    最终判定规则(等价形式)

    无解条件
    存在一个连续的空花盆段,满足:

    1. 该段左右两边都有花(即不是靠边界)
    2. 该段的长度是奇数

    否则有解。


    示例验证

    s=11011011s = 11011011(第 3 个样例):

    • 段:11 0 11 0 1111\ 0\ 11\ 0\ 11 → 两个长度为 11 的段,左右都是 11,长度 11 为奇数 → 无解 → NO

    s=0100s = 0100(第 1 个样例):

    • 段:0 1 000\ 1\ 00 → 第 1 个 00 左边无(边界),不算;第 2 段 0000 长度 22 偶数,右边无(边界),不算 → 有解 → YES

    时间复杂度

    O(n)O(n) 遍历一次字符串,总复杂度 O(n)2×105O(\sum n) \le 2\times10^5


    对应代码(已给出)

    你的代码完全实现了上述逻辑。

    #include <bits/stdc++.h>
    using namespace std;
     
    void solve() {
        int n; cin >> n;
        string s; cin >> s;
        bool ok = true;
        bool curr = (s[0] == '1');
        int cnt = 0;
        for (int i = 0; i < n; i++) {
            if (s[i] == '0') cnt++;
            if (i == 0) continue;
            if (s[i] == s[i-1] && s[i] == '0')
                curr = false;
            if (s[i] == s[i-1] && s[i] == '1') {
                if (curr && cnt % 2 == 1)
                    ok = false;
                curr = true;
                cnt = 0;
            }
        }
        if (curr && cnt % 2 == 1 && s[n-1] == '1')
            ok = false;
        cout << (ok ? "YES" : "NO") << "\n";
    }
     
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int T; cin >> T;
        while (T--) solve();
    }
    
    • 1

    信息

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