🤖 这是题做完后的复盘对话录原稿,不是从零做题的过程记录——题已经 AC 了,复盘的目的是把"猜对了一半"的直觉补完,搞清楚为什么这条 if 是对的、为什么这道题只值 800。蓝色 callout 是 Claude,橙色 callout 是 zzy。
原题:Codeforces Round 2225 (Edu 189) Problem B - Alternating String(rating 800)
背景:题已 AC(submission 373228609),代码核心是数 相邻相等对子(bad pair)的个数 ,判 即 YES。比赛时手滑写成 而非 WA 一发。这次复盘是要把"猜对了一半"的直觉补完,让 这条结论从结构上讲清楚——也就回答了它为什么只值 800。
第 1 步:题意 + 数据范围核对
🤖 Note: Claude
先把题面 + 约束钉一下,确认我们在同一频道:
- 串 只含
a/b,长度 , ,时限 2s。 - 至多一次操作:选区间 ,可选地把 内每个字符
ab(invert),然后必须把 整段反转(reverse)。 - 问最后能否变成 alternating(任意相邻两位不同)。
数据规模直接给了线性时间预算,签到题量级。先确认这条阅读没问题,再走第 2 步——为什么数 bad pair 就够了。
第 2 步:抓不变量
🤖 Note: Claude
先把第二步 invert 暂时放一边,只看 reverse 这一动作。
定义bad pair:位置 满足 。把 里所有 bad pair 按下标 分三类:
- 类 P: (这对的两端都在被反转的段内)
- 类 Q: 或 (恰好骑在被反转段的边界上)
- 类 R: 或 (这对的两端都在被反转段外)
问题:reverse 之后,这三类位置里哪一类的"等 / 不等"状态铁定不变?哪一类有可能变?
(拿abbaba这种串选一段在纸上反一下,盯紧每个相邻对反转前后是否还相等,比脑算靠谱。)
🧑 Note: zzy
如果两段都在反转段内,那么是不变的。如果两段刚好骑在反转边界上,那就是比较 trick,不知道是什么情况,你也不知道反转弯会怎么样,因为这和段有关系。如果两段都在反转外,肯定不变。当然,如果在反转段的边界上有办法解决,因为它还有操作可以反转。如果反转段反转后还一样,就再反转一下字符就行了。说白了,只要有一个在段内,那么这个 bad pair 肯定是可以被消掉的不对不对,只有在这个边界上,它才可以被消掉的。
🤖 Note: Claude
对。三类的状态分别是:
- P 类(内部):reverse 把 翻成 ,相等性守恒;invert 同时翻
a/b,相等性也守恒。一定保留。 - R 类(外部):完全没碰。一定保留。
- Q 类(边界): 旁边的字符从 换成(也许 invert 过的) ; 旁边的字符从 换成(也许 invert 过的) 。有可能变。
立刻得到必要条件:原串里所有 bad pair 必须挤在 这两个位置上才有救——也就是 。
这就是你 AC 那条if的"必要"那一半,也是这道题为什么定到 800:核心就一个不变量。剩下"充分"那一半,下一步走。
第 3 步:充分性收尾
🧑 Note: zzy
讲到这里题就做完了,充分性这一半不用再细抠,结论我自己脑算就行。
🤖 Note: Claude
那 mentor 我直接把充分性收掉,留个完整记录:
设两个 bad pair 在位置 ,要让 ,所以 ,被操作的子串是 ,硬选定。
操作后 boundary 字符:
- 位置 旁的新字符 = 或 (取决于是否 invert);
- 位置 旁的新字符 = 或 (同上)。
需要 新字符 且 新字符 ,化简后两个边界条件殊途同归,都是同一句" 和 关系": - (一个
aa、一个bb,异色):reverse 单刷就够,boundary 字符互换正好掐准; - (两个都
aa或都bb,同色):reverse + invert,invert 把字母翻一下 boundary 才不等。
两种情形都覆盖 一定 YES。 把上述退化(让一边 boundary 落在串端外,只剩一个边界要修,同样一定能成)。 trivial。
综合: YES,这就是题解里那条if的全部底气。这道题为啥定 800:核心只有一个不变量——reverse + invert 在「相邻相等」这件事上对内部和外部都是恒等,只有两个边界能动。剩下的全是把这个不变量翻译成代码。
复盘要点: - 比赛 bug:把
cnt > 2写成cnt > 20——签到题这种字面 typo 得养成 submit 前肉眼扫一遍 cutoff 数字的习惯; - 思考过程:你"猜到了一半"对应的就是必要侧(边界能动),充分侧的 case-work 没顶住单纯是因为已经验过样例所以没回头补;
- 知识点:操作不变量类签到题——遇到「最多一次 reverse / swap / 区间操作」立刻去找"什么量在操作下守恒",cnt 这种"边界数"是高频答案。
心路历程(WA → AC)
-
第一发 WA:cutoff 写错——
if (cnt > 20)而非if (cnt > 2),签到题字面 typo。教训:submit 前肉眼扫一眼临界数字;多写几个 #define 常量(比如MAX_BAD_PAIR = 2)也行,但更直接的是 cutoff 行单独看一眼。 -
第二发:把 typo 修了直接 AC(submission 373228609)。
AC 代码
核心就是数相邻相等对子 cnt,判 cnt <= 2:
1 | void Solve() { |
完整源码(含 debug 模板)见末尾附件 solution.cpp.txt。
📎 附件
-
mentor.pdf:完整带教对话录 PDF 版(贴在下方)。 -
solution.cpp.txt:完整 C++ 源码(重命名为.txt才能上传,下载后改回.cpp编译;含 UTF-8 BOM,中文注释正常)。