模拟、递推与边界
本节目标
把题意翻译成状态、操作顺序与边界条件,并用循环不变量检查实现。
基础实现题看起来是在考语法,真正要做的是把自然语言的题意转换为可执行的状态、明确的操作顺序和可检查的边界。先把这些约定写清楚,代码才会短而可靠。
识别信号
出现“按规则逐个处理”“对每一位做相同操作”“下一项由前面的结果得到”时,通常不需要寻找复杂技巧:先考虑规则模拟、数位与进位,或从已知状态递推。
“模拟”不是照抄题意,而是先确定状态、规则优先级和更新顺序。同一轮中若既要读取旧状态又要写入新状态,就必须说明读到的是哪一个版本;规则有多个分支时,也要先写出它们的优先级。
通用建模流程
- 写下状态:循环中哪些变量或数组位置代表当前结果。
- 把题目规则拆成一次操作,并确定各规则的判断优先级。
- 确定更新顺序:本轮读取旧状态后再写入,还是可以原地更新。
- 用一个最小例子手推首轮、中间轮和最后一轮。
- 最后单独检查输入为空、循环是否进入,以及答案应从哪个状态返回。
循环不变量与边界清单
循环不变量是每轮都不变的事实。循环开始前,要能说清已处理部分是什么、未处理部分是什么;每轮结束后,要能说清新处理的一个元素怎样让这个事实继续成立。例如,处理数位时,已扫描的后缀已经是正确结果;构造行时,已写出的元素已经满足本行的递推关系。
提交前逐项检查:
- 空输入是否应该直接返回空结果或零值;
- 单元素是否仍满足初始化和返回位置;
- 首尾位置会不会访问不存在的前驱或后继;
- 全进位会不会需要新增最高位;
- 第一层初始化是否已经给出递推所需的基例。
三类基础模型
规则模拟
遍历输入或计数范围,按已写明的优先级选择输出或操作。规则重叠时,先处理更具体的情形,避免较宽泛的条件提前截走分支。
数位与进位
从最低位向高位处理,把进位作为状态的一部分。每轮先合并当前数位和进位,再写回当前位并更新下一轮进位;循环结束后还要检查是否残留进位。
从已知状态递推
先给出第一层或第一项,再说明新状态依赖哪些已经确定的状态。若依赖左右相邻位置,边界位置需要单独按定义处理,不能套用中间位置的公式。
母题序列
按必学顺序完成下列四题;这里用于练习框架与检查方法,不展开它们的完整解法:
常见误区
- 直接把题目句子翻成条件分支,却没有定义每个变量保存的是旧值还是新值。
- 让首尾位置进入只适用于中间位置的访问逻辑。
- 只在普通样例中检查进位,遗漏所有数位都变化的情况。
- 没有初始化基例,就开始使用递推式。
- 根据最终输出倒推循环正确性,而没有在每轮结束后检查不变量。
迁移方向
以后遇到更长的模拟题、二维表格构造或简单动态规划时,仍可先问同样的问题:状态是什么?规则按什么顺序发生?循环开始前与结束后各自已知什么?哪几个边界需要独立定义?能先回答这些问题,就能把基础题中的可靠实现迁移到更复杂的模型。