01 / 本课学习路线
本课学习路线
预计约 120 分钟,具体时长根据待订正题目数量调整
02 / 订正流程与完成条件
订正不是重做一遍:四个动作,每道错题各走一次
「再做一遍」不是修复。订正的定义是:说清第一次错在哪一类、用一个最小用例复现它、改掉它、证明改对了、再不看旧代码重写一次。这套流程会一直用到模块 8 的模拟考试复盘。
| 动作 | 做什么 | 产出 | 对应正文 |
|---|---|---|---|
| ① 分类 | 按第一次出错的原因归到六类之一 | 登记表的「首次错误类型」一栏 | 第 03 节 |
| ② 定位并修复 | 找到导致错误的那几行代码或那条被漏读的规则,改掉 | 登记表的「错误原因」「修复动作」 | 第 03、04 节 |
| ③ 最小验证 | 构造一个只触发该错误的输入,修复前失败、修复后通过 | 登记表的「触发用例」「最小验证」 | 第 04、05 节 |
| ④ 独立重写 | 不看旧代码从空文件重写整题,用复测清单验证后提交 | 登记表的「独立重写」 | 第 06 节 |
完成条件:本课没有新的必做题;下面两道「重做任务」是复习题,用于独立重写,不计入完成状态。本课算完成 = 勾选全部学习完成检查(含把订正不了的题写明具体问题)。先用失败用例检查原错误是否消失,再跑边界用例、独立重写并提交;仍有疑问时记下具体输入与差异。
| 来源 | 题号 | 判题结果 | 先猜的错误类型 | 订正状态 |
|---|---|---|---|---|
| 阶段测验第 1 题 | P2492 | 答案错误(WA) / 运行错误(RE) / 未完成 / 通过(AC) | — | 未开始 |
| 阶段测验第 2 题 | P2499 | 同上 | — | 未开始 |
| 第 1~5 课 未通过的必做题 / 进阶题 | 逐题填 | 填判题结果 | — | 未开始 |
「先猜的错误类型」在第 03 节按判定信号确认后再改;AC 的题只登记曾经改过的具体问题,不进入订正流程。
03 / 六类错误的判定与定位
判定信号、定位步骤、修复动作、最小用例怎么构造
分类不靠感觉,靠信号:先看判题结果是哪一种,再用下面的问题逐个排除。一道题可能同时有两类错,先修最早暴露的那一类。
| 类型 | 判定信号 | 定位步骤 | 修复动作 | 最小用例怎么构造 |
|---|---|---|---|---|
| 读题 | 样例能过、某些用例 WA;或对规则的理解与题目页说明不一致 | 重新写题目要求清单(第 2 课 的模板),逐条对照代码,找出没有实现或实现错的那一条 | 按那一条改代码,并在注释里写上「规则 N」 | 构造一个只违反那条规则的输入(案例 A:第一段为 0) |
| 建模 | 所有用例都错或大面积错;状态、指针、计数的含义说不清 | 把变量含义写在纸上,用题面示例逐步手推,找到第一次与期望不一致的步骤 | 重画状态或指针的变化规则,改那一步 | 取题面示例或比它更短的输入(案例 B:9 3) |
| 边界 | 只有特定输入错:空输入、最小值、最大值、重复值、非方阵 | 列出四类边界输入逐个手算 | 补上判断或改循环范围 | 就是那个边界输入本身(如 1×1、n=1、空段) |
| 复杂度 | 超时(TLE),且不是读入问题 | 估算最坏循环次数,与数据范围比 | 换掉多余的整表扫描或列表 in | 构造最大规模输入计时(本模块的题不会遇到) |
| 语言 | 运行错误(RE)或结果对不上却找不到逻辑错 | 写 3 行小实验验证可疑的语言行为:负下标、input() 越过末尾、整数除法方向、字典遍历中修改 | 换成明确的写法(先判边界、只读需要的行数) | 触发该语言行为的最短输入(如比程序多读一行) |
| 输出格式 | 答案错误(WA)或格式错误(PE),数字都对 | 把自己的输出与期望输出逐字节对比(第 1 课 的 diff 方法) | 改分隔符、末尾换行、小数位数、固定文本大小写 | 题面示例(案例 C:xyxyXX 的末尾分号) |
登记时的一条硬要求:「错误原因」必须具体到能据此直接改代码——「粗心」「没注意」不符合要求,「第一段范围写成 0~255」符合。写不出具体原因,说明还没定位到,回到定位步骤。
04 / 三个完整订正案例
失败用例 → 定位 → 修改前后对照 → 复测
三个案例都来自本模块真题里真实会出现的错误,每个都走完整流程;你的错题按同样的格式处理。
案例 A · 读题类:P2508 把第一段范围写成 0~255
判题结果: 答案错误(WA);题面示例 128#0#255#255、1#0#0#0 都能过 失败用例: 0#1#1#1 期望 invalid IP 实际 65793(把它当合法地址拼了) 定位: 重写题目要求清单 → 第 ④ 条「第一段 1~128」没有单独实现,用的是四段统一 0~255 修复: 第一段单独判 1 <= a <= 128(见下方前后对照) 复测: 0#1#1#1 → invalid IP ✓ 129#0#0#0 → invalid IP ✓ 128#0#255#255 → 2147549183 ✓ 1#0#0#0 → 16777216 ✓
案例 A 修改前(片段)
Python# 修改前(P2508 第 3 项检查):把第一段也按 0~255 判
a, b, c, d = (int(p) for p in parts)
if not all(0 <= x <= 255 for x in (a, b, c, d)):
print("invalid IP")案例 A 修改后(片段)
Python# 修改后:第一段单独按 1~128 判(题目要求清单第 ④ 条)
a, b, c, d = (int(p) for p in parts)
if not 1 <= a <= 128 or not all(0 <= x <= 255 for x in (b, c, d)):
print("invalid IP")只改了检查条件那一行;完整程序在第 2 课 第 06 节展开区。修改前后各跑一次四个复测用例,修改前第一个用例失败、修改后全部通过——这才是「修复生效」。
案例 B · 建模类:P2529 上边界不收缩(漏掉 top += 1)
判题结果: 答案错误(WA);n=1 这类单格输入能过 失败用例: 9 3 期望 1 2 3 / 8 9 4 / 7 6 5 实际 1 2 4 / 9 * 5 / 8 7 6 定位: 用第 5 课 第 06 节的四段推演逐段对照:上行填完 1 2 3 后 top 仍是 0,右列从第 0 行重填,(0,2) 被 4 覆盖,(1,1) 永远轮不到——边界收缩规则少画了一条 修复: 每填完上行就 top += 1(见下方前后对照) 复测: 9 3 → 1 2 3 / 8 9 4 / 7 6 5 ✓ 9 4 → 1 2 3 / * * 4 / 9 * 5 / 8 7 6 ✓ 1 1 → 1 ✓
案例 B 修改前(片段)
Python# 修改前(P2529):上行填完没有收缩上边界
for c in range(left, right + 1): # 上行:从左到右
if num > n: break
grid[top][c] = str(num); num += 1
for r in range(top, bottom + 1): # 右列:从上到下——top 仍是 0,第 0 行被重填
if num > n: break
grid[r][right] = str(num); num += 1
right -= 1案例 B 修改后(片段)
Python# 修改后:每填完一段就收缩对应边界
for c in range(left, right + 1): # 上行:从左到右
if num > n: break
grid[top][c] = str(num); num += 1
top += 1 # 上边界收缩,右列从新的 top 行开始
for r in range(top, bottom + 1): # 右列:从上到下
if num > n: break
grid[r][right] = str(num); num += 1
right -= 1建模类错误的定位工具是「逐段手推表」:把第 5 课 第 06 节四段推演每一段的边界值写出来,与程序的实际行为对照,第一处不一致就是要改的地方。完整程序在第 5 课 第 07 节展开区。
案例 C · 输出格式类:P2562 漏掉最后一个分号
判题结果: 答案错误(WA)或格式错误(PE),取决于判题器;计数与顺序都对 失败用例: xyxyXX 期望 x:2;y:2;X:2; 实际 x:2;y:2;X:2 定位: 逐字节对比:期望输出比我的多一个字符——末尾的分号;题目页示例每项后面都有分号,包括最后一项 修复: 每项后面拼一个分号,不用 join 的分隔语义(见下方前后对照) 复测: xyxyXX → x:2;y:2;X:2; ✓ abababb → b:4;a:3; ✓
案例 C 修改前(片段)
Python# 修改前(P2562):用分号连接,最后一项后面没有分号
print(";".join(f"{ch}:{cnt}" for ch, cnt in items))案例 C 修改后(片段)
Python# 修改后:每项后面都跟一个分号(题目页示例 x:2;y:2;X:2;)
print("".join(f"{ch}:{cnt};" for ch, cnt in items))输出格式类错误几乎都能靠第 1 课 的 diff 比对定位:差在哪个字节,就改哪一处。完整程序在第 3 课 第 07 节展开区。
05 / 错题登记与最小验证
登记模板、填好的示例、最小用例的三个要求
登记表是订正的账本:每道错题一条,订正完把「独立重写」一栏改成「通过」。下面先给空模板,再给案例 A 填好的样子。
错题登记模板(每题一条)
Python# 错题登记(每题一条,在错题订正课逐条关闭)
# 题号: ____
# 首次错误类型: 读题 / 建模 / 边界 / 复杂度 / 语言 / 输出格式
# 触发用例: ____
# 错误原因: ____(一句具体、可验证的话,指出导致错误的代码或规则)
# 修复动作: ____
# 最小验证: 构造只触发该错误的用例,修复后先跑它
# 独立重写: 未做 / 通过 / 未通过(原因: ____)复制进你的错题本,每订正一项填一条;如果暂时无法准确描述错误原因,请结合失败用例和代码位置进一步检查,再回到六类错误原因重新分类。
填好的示例(案例 A)
Python# 错题登记(案例 A 填好的样子)
# 题号: P2508
# 首次错误类型: 读题
# 触发用例: 0#1#1#1(期望 invalid IP,我的程序输出 65793)
# 错误原因: 第一段范围写成 0~255;题目要求第一段是 1~128
# 修复动作: 第一段单独判 1 <= a <= 128
# 最小验证: 0#1#1#1 → invalid IP;129#0#0#0 → invalid IP;128#0#255#255 → 2147549183
# 独立重写: 通过(不看旧代码,从空文件重写后四个用例全部一致)「触发用例」写明期望与实际;「错误原因」写到能直接改代码;「最小验证」至少三条:触发错误的、边界另一侧的、题面示例。
| 要求 | 含义 | 反例 |
|---|---|---|
| 只触发这一类错误 | 修复前失败、修复后通过,且不涉及其它规则 | 拿整份题面样例当最小用例——它可能同时经过多条规则 |
| 尽量短 | 手算能在 1 分钟内得到期望输出 | 用 20×20 的网格验证「第一段范围」这类规则 |
| 带期望输出 | 登记时写清期望与实际 | 只写「输入 0#1#1#1」不写期望 |
每订正一项做一次最小验证:不要直接重交原题,先跑最小用例确认修复真的生效,再独立重写整题。这个习惯到模块 4 调试动态规划(DP)、模块 7 调试量化数值时,会成倍地省时间。
06 / 独立重写与复测清单
不看旧代码从空文件重写,用清单验证后再提交
独立重写检验的是「离开旧代码还能不能写对」。重写前只允许看题目页和自己的题目要求清单,不看旧代码、不看参考程序。
| 题目 | 题面示例 | 边界用例 | 错误专项用例 |
|---|---|---|---|
| P2529 螺旋数字矩阵 | 9 4 → 1 2 3 / * * 4 / 9 * 5 / 8 7 6 | 1 1 → 1;10 1 → 一行;4 4 → 一列 | 11 3(一个 *);9 3(正好填满、最后一圈只剩中心) |
| P2508 IPv4 转整数 | 128#0#255#255 → 2147549183;1#0#0#0 → 16777216 | 128#255#255#255 → 2164260863 | 0#1#1#1 / 129#0#0#0 / 1#256#0#0 / 1#0#0 / a#0#0#0 / 1##0#0 → 全部 invalid IP |
| P2492 字符串加密 | 题面示例(题目页给出输入与输出) | 长度 10 的原文(第七个字母起偏移要取余) | 2 组输入,两行都要输出——期望输出以交卷后的测验解析为准 |
| P2499 箱子之形摆放 | 题面示例(题目页给出输入与输出) | ABC 1;A 5(一行有字母、其余空行) | ABCDEFGH 4(两端折返)——期望输出以交卷后的测验解析为准 |
需要重算时,参照第 5 课第 06 节、第 2 课第 06~07 节的推演;阶段测验两题参照交卷后解析的第 02~03 节。重写后先跑清单再提交;提交通过后把登记表的「独立重写」改成「通过」。
重写仍未通过怎么办:对比两次失败用例和代码位置——如果是同一个用例失败,说明错误原因没定位准,回到第 03 节重新分类;如果是新的用例失败,登记一条新的错题。两次都不过也不算失败,登记表里写明具体问题,带着它进下一模块。
07 / 迁移练习与参考答案
分类练习、找错练习,以及没有错题的同学做什么
每题先自己做,再展开答案。
练习 1(分类):下面五个失败描述各属于六类中的哪一类?① P2480 样例通过,输入 1 2 100 1 50 输出 Walk(期望 Taxi);② P2503 输入 2 行 3 列时抛出下标越界异常;③ P2562 输出 X:2;x:2;y:2;(期望 x:2;y:2;X:2;);④ P2483 输出 5.0(期望 5.00);⑤ P2484 用 input() 读了三次,第三次抛出 EOFError。
展开练习 1 答案
① 读题(公里没换算成米,漏了题目要求的单位);② 边界(行列接反或访问前没判边界——用非方阵样例暴露);③ 读题(并列规则「小写在前」理解成了默认字母顺序);④ 输出格式(没按两位小数格式化);⑤ 语言(input() 越过输入末尾的行为)。判定依据:①③样例能过而特定用例错 → 读题;②只有非方阵错 → 边界;④数字对格式错;⑤运行错误且逻辑无错。
练习 2(找错并写最小用例):一位同学的 P2480 把耗时算成 taxi = X / M + L、walk = Y / N(没有乘 1000)。写出它的错误类型、一个最小用例(含期望与实际输出)和修复动作。
展开练习 2 答案
类型:读题(漏了「距离是公里、速度是米/分钟」的单位换算)。最小用例:1 2 100 1 50——正确:计程车 1000÷100+1 = 11 分钟、步行 2000÷50 = 40 分钟 → Taxi;错误程序:1÷100+1 = 1.01、2÷50 = 0.04 → Walk。修复:X、Y 乘 1000 后再算(或用第 1 课 的整数交叉相乘)。复测:题面样例 50 5 500 30 90 → Walk 仍然通过。
练习 3(没有错题的同学):把本模块印象最浅的一道必做题不看旧代码独立重写并用第 06 节的清单复测(清单没列的题,用原课正文的手算例和错误表复测);然后做进制与位运算的进阶练习——P2531 的十六进制变式:k=255、幸运数字 15、m=16,输出是多少?k=241 呢?
展开练习 3 答案
255 = 15×16 + 15 → 十六进制两位都是 15 → 输出 2;241 = 15×16 + 1 → 各位 [1, 15] → 幸运数字 15 出现 1 次 → 输出 1。用短除法逐位取余、按位比较整数(不要拼成字符串再数子串),第 2 课 第 08 节有逐步表。
08 / 复习入口与完成条件
订正完成之后做什么
订正只针对本模块;每类错误对应的课入口如下,订正完成后按顺序进入模块 2。
| 错误类型 | 回到哪里 | 重点看什么 |
|---|---|---|
| 读题 / 输出格式 | 输入输出规则、数据范围与精度 | 第 03 节题目要求清单模板、第 05 节格式化表 |
| 建模 | 字符串规则模拟 | 第 03 节规则清单、第 05 节状态扫描手算 |
| 边界 / 语言 | 二维数组、坐标与边界处理 | 第 04 节边界函数与负下标演示 |
| 复杂度 | 标准输入输出与首次独立提交 | 第 04 节数据范围换算表 |
| 并列规则 | 哈希表:计数、去重与查询 | 第 05 节排序键推演 |
完成条件:本课算完成 = 勾选全部学习完成检查(含把订正不了的题写明具体问题);两道重做任务是复习题,不计入完成状态。错题订正完成后,先把本模块最没把握的必做题独立重写一次;还有余力,再做进制与位运算的进阶练习(做过 P2531 的同学换十六进制方向自练)。仍然不加新的必做题——模块 2 的内容在后面。
09 / 练习
按顺序完成本课的任务
编程任务已通过 0/2 道
错题登记:每题一条,逐条订正
重做任务 1自主练习练习重点:本模块全部错题按六类错误原因登记,写清触发用例与错误原因;预计用时:40 分钟
完成标准:每道错题都记录了具体错误原因、触发用例和修正方法
需要时查看提示
错误原因要具体到能据此直接修改代码:「粗心」「没注意」不符合要求,「第一段范围写成 0~255」符合。登记模板与填好的示例见第 05 节。
P2529 · 螺旋矩阵 · 独立重写
重做任务 2练习重点:不看旧代码,从空文件重写螺旋收缩;预计用时:25 分钟
完成标准:不查看上一课「模块 1 · 阶段测验」的代码,独立写出边界收缩的四个变量并验证
需要时查看提示
先在纸上画 4×3 的收缩过程再动手。写完用第 06 节清单里 n 不整除 m 的用例(11 3)验证 * 填充。
P2508 · IPv4 转整数 · 独立重写
重做任务 3练习重点:合法性清单一次写全:段数、纯数字、第一段 1~128;预计用时:20 分钟
完成标准:提交前根据题目要求写全校验清单,并用边界用例检查各项条件
需要时查看提示
重做前先不看资料写出合法性清单,再对照输入输出规则课(模块 1 · 第 2 课)的要求笔记查漏。第 06 节清单里的六种非法输入都应输出 invalid IP。
提交结果
提交结果说明与处理方法
- WA
答案错误
独立重写仍未通过:对比两次失败用例和代码位置,重新检查错误原因并更新登记表(第 06 节末段)
- PE
格式错误
还是格式错就把输出段单独抽出来,和样例逐字节对比(案例 C)
- RE
运行错误
语言类错题:写 3 行小实验验证(负下标、文件尾异常(EOFError)、整数除法方向)
- TLE
超时
本模块的题都能在时限内跑完,超时先查是不是多套了一层循环,记成建模类错题
- AC
通过
在登记表中将这条错题标记为已完成;所有错题完成修改、通过验证并更新状态后,本次错题订正的订正任务完成
10 / 学习完成检查
本课学习完成检查
完成本课需要:没有新的必做题,勾选全部学习完成检查即算完成。登录后,勾选记录会保存到账号,并更新课程总览的完成状态。