1 条题解
-
0
好的,根据你给出的代码,下面是详细的题解。
题意简述
有 个花盆排成一行,字符串 中 表示有花(不可放兔子), 表示空(必须放一只兔子)。
每只兔子可以选择向左或向右看,但如果它看向的下一个花盆里有兔子,或者另一只兔子正从对面看过来(即两只兔子准备交换位置),则它们都不会跳。目标是判断是否存在一种方向安排,使得最终没有兔子实际发生跳跃。
问题转化
- 花盆里如果有花(),没有兔子,可以看作“墙”。
- 空花盆()里都有兔子。
- 兔子不跳的条件:
对任意相邻的两个空花盆 和 ,不能出现 向右看且 向左看的情况(因为那样它们会互相跳向对方的位置)。
同时,也不能出现某个兔子看向一个已经有兔子的位置(即看向相邻但非空的另一侧时,如果那边也有兔子且方向是朝这里,就会冲突)。
实际上,经过分析(可参考官方题解或已知结论),这个问题的核心简化是:
在一个连续的“空花盆段”中,如果它的长度是奇数,且两端都不是边界(即两端都被花包围),则无解。
为什么?因为:
- 在连续的空花盆段中,兔子必须安排方向使得不会产生相向而行。
- 长度为 的连续空位,必须像 这样安排,中间有一个“分界点”,左边全向右,右边全向左。
- 如果 是偶数,可以平分,左右各 。
- 如果 是奇数,则必须有一边的兔子比另一边多 ,那么多出的那只兔子如果看向段外,但段外是花(墙),则它看向墙就不会跳,这样是可以的。但如果段的两端都被花包围,那么两端兔子看向墙,中间必须有一个“中心兔子”向某个方向,但这会导致对面方向的兔子与它相向。经过分析(与代码对应),此时无解。
代码逻辑对应
代码中将原问题转化为对连续空段的奇偶性判断,并结合段是否被花包围来判定。
代码中:
curr表示当前是否处于一个被 包围的段(即左右都是 的段)?其实更准确地说,curr标记的是上一个遇到的 是否与当前段构成“两端有 ”的情况。cnt记录当前连续 的长度。- 遍历时:
- 遇到 ,
cnt++ - 遇到 ,说明连续 在继续
- 遇到 ,说明两个 之间夹了一段 ,此时:
- 如果
curr为真(表示上一段的左边是 ,即这一段 左右都是 ) - 且
cnt是奇数 - 则无解(
ok = false) - 然后重置
curr = true(新段左边也是 ?其实这里是标记下一个段也是被 包围)
- 如果
- 最后,遍历结束后,如果最后一段 也是被 包围(
curr真)且长度是奇数,也无解。
- 遇到 ,
最终判定规则(等价形式)
无解条件:
存在一个连续的空花盆段,满足:- 该段左右两边都有花(即不是靠边界)
- 该段的长度是奇数
否则有解。
示例验证
例 (第 3 个样例):
- 段: → 两个长度为 的段,左右都是 ,长度 为奇数 → 无解 →
NO✅
例 (第 1 个样例):
- 段: → 第 1 个 左边无(边界),不算;第 2 段 长度 偶数,右边无(边界),不算 → 有解 →
YES✅
时间复杂度
遍历一次字符串,总复杂度 。
对应代码(已给出)
你的代码完全实现了上述逻辑。
#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
- 上传者