E9 阅读程序专项(40 分)

这是全卷最大的一块。 3 篇程序,每篇 3 道判断题(1.5 分)+ 2~3 道选择题(3 分),共 40 分

📝 本章的例子全部来自 E11 里那 7 套真题,每一条结论都是实际编译运行验证过的。


一、先认清这块是怎么考的

每篇程序后面挂着两类题:

题型 分值 特点
判断题 1.5 分 × 3 只有「正确 / 错误」,蒙也有 50%
选择题 3 分 × 2~3 四选一

⚠️ 判断题绝不能空着。 一篇 3 道判断题就是 4.5 分,三篇 13.5 分——全空等于送人 13 分。

判断题的六种固定考法

考法 例子 破法
给一组输入问输出对不对 「当输入为 2 2 2 时输出为 1.7321 手动模拟算出来
改一行代码问结果变不变 「把 i<=n 改成 i*i<=n 结果不变」 想清楚这行到底管什么
问会不会出错/死循环/越界 「输入 n=1001n=1001 时不会下标越界」 查数组大小、查除零、查递归出口
问某个断言是否「总是」成立 「输出总是四位小数」「答案一定小于 2n2n 找反例,特别是边界
问函数在算什么 f 返回的是最长公共子串的长度」 看清是子串还是子序列
问某行会不会被执行 「第 15 行不会被执行」 找到那行的触发条件

二、★ 唯一可靠的方法:手动模拟表

别「看懂大意」,要「逐行填表」。

拿到程序后在草稿纸上画一张表,每一列一个变量,每一行一次循环

轮次 |  i  |  j  |  a[i]  |  ans  |  说明
-----+-----+-----+--------+-------+--------
 初  |  -  |  -  |   -    |   0   |
  1  |  1  |  0  |   3    |   1   |
  2  |  2  |  0  |   1    |   1   |
  3  |  3  |  1  |   5    |   2   |  ← j 动了

📝 只填题目问到的那几步就够——比如问「输入 8 时输出什么」,就模拟到能看出规律为止,不必跑完。

⚠️ 在脑子里过一遍是这类题唯一的失分原因。 栈/队列的模拟尤其如此(CSP 2025 第 15 题、CSP 2024 第 13 题)。


三、★ 七个「先看这里」的检查点

拿到一段程序,按这个顺序扫一遍,大部分判断题当场就有答案:

① 数组开了多大?循环跑到哪?

int a[1000];          // 合法下标 0 ~ 999
for (int i = 0; i < n; i++) cin >> a[i];   // n = 1001 就越界

⚠️ CSP 2021 第 16 题:数组 a[1000],问「n=1001n=1001 时不会越界」——

② 有没有除以 0 / 模 0 的可能?

⚠️ CSP 2019 第 16 题:把 i = 1 改成 i = 0,第一次就算 n % 0程序直接崩溃

③ 递归的出口是什么?规模真的在变小吗?

⚠️ 「递归写错了」不等于「一定死循环」。 CSP 2025 第 16 题把 gcd(b, a%b) 改成 gcd(a, a%b)——实测不会死循环b 仍单调递减到 0),只是返回值恒等于 a选项 C「陷入死循环」是最诱人的错误答案。

④ 循环变量的边界差一了吗?

i <= n vs i < nmid vs mid-1n-1 vs n——差一是阅读程序题的头号考点。

⑤ 题目「没排除」的输入是什么?

⚠️ 这是判断题 ④ 类的通用破法。

CSP 2023 第 16 题:题面说「输入的所有数都是不超过 1000 的正整数」,但没说能构成三角形。输入 1 1 5 时海伦公式根号内是负数 → 实测输出 nan,所以「程序总是输出四位小数」是错的。

📝 读题面的限制条件时,逐条问:它把什么排除了?没排除的那些呢?

⑥ 有没有 n=0n=0n=1n=1 的边界?

⚠️ 看到「一定」「总是」,第一反应是去试最小的输入。

📝 一个 n=1n=1 能把三道题的答案从 C 改成 D。

⑦ 类型对不对?

⚠️ 溢出要真算,不能想当然。 CSP 2022 第 18 题问「mid * mid 会不会溢出」——实测穷举 n=047000n=0\sim47000 的全部二分过程,最大 mid*mid 只有 5.5×1085.5\times10^8,远没到 int 上限。所以「有缺陷、应当强转 64 位」这句话是错的

📝 但这个警觉本身是对的:看到 mid*mid 先想溢出,然后去查数据范围再下结论。


四、★ 五个高频陷阱

陷阱一:问的是「函数返回值」还是「程序输出」

⚠️ CSP 2024 第 18 题customFunction(2,3)返回值88,但程序输出的是 pow(8,2) = 64。判断题问「返回值为 64」——

📝 把题干里的「返回值」「输出」「第一行」「第二行」圈出来。

陷阱二:子串 vs 子序列

定义
子串 连续的一段
子序列 可以不连续,但顺序不变

⚠️ CSP 2023 第 17 题整道题都建立在这个区别上:f 求的是最长公共子序列,所以 g 判断的并不是「循环同构」。第 (6) 小题 csppscspsccp 看着不是循环移位,但因为是子序列,实测照样返回 1

📝 CSP 2022 第 14 题(abcab 有几个不同子串)也在考这一对词。看到就停一下。

陷阱三:「一半的程序里装死」的 bug

⚠️ 同一个 bug,在有的程序里会暴露,在有的程序里完全看不出来。

比如 i <= n 多读一个元素:如果后面还要读别的数据,输入会整体错位(症状明显);如果只是求和,可能一点问题都没有。

📝 所以「改一行问结果变不变」的题,必须针对题目给的具体程序去想,不能套经验。

陷阱四:「样例过了」不等于「写对了」

⚠️ CSP 2023 第 19 题:那个二分找缺失元素的程序,如果缺的恰好是倒数第二个元素,返回值会和「连续」的哨兵值撞车,程序误报「Sequence is consecutive」。实测确认。

📝 这不影响选项判断,但它说明:能过样例的程序也可能是错的。

陷阱五:给一串输出,只要有一个数不同就是错

⚠️ CSP 2021 第 16 题:题目说输出 3 4 3 17 5实测是 3 4 3 17 4——只差最后一个。

📝 逐个算完,别算前两个对上了就打勾。


五、几个反复出现的程序模型

认出模型,半道题就到手了。

看到这样的代码 它在干什么
for (; x; x &= x-1) ret++; 数二进制里 1 的个数(popcount)
return x & -x; 取最低位的那个 1(lowbit)
gcd(a,b) = b ? gcd(b, a%b) : a 辗转相除求最大公约数
for (i=2; i*i<=n; i++) if (n%i==0) 试除法判素数 / 分解质因数
if (!a[i]) { b[m++] = i; } ... if (i%k==0) break; 线性筛(欧拉筛)
dp[i] = min(dp[i-1], dp[i-2]) + cost[i-1] 爬楼梯型一维 DP
if (x[i]==y[j]) v[i][j]=v[i-1][j-1]+1; else max(...) 最长公共子序列 LCS
dp[i][j] = 1 + min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) 编辑距离
candidate/count,相同 ++ 不同 --,归零换人 摩尔投票(求多数元素)
while (!q.empty()) { ... 四方向 ... } BFS / 洪水填充
找区间最小值当根、左右递归 笛卡尔树(结构同快排)

📝 这 12 个模型覆盖了 7 套真题里的绝大多数阅读程序题。 认出模型之后,很多判断题不用模拟就能答(比如「LCS 的返回值 ≤ 较短串长度」显然成立)。


六、答题顺序建议

1. 先把程序从头到尾读一遍,判断它在算什么(对照上面的模型表)
2. 做「问输出是什么」的题 —— 老实模拟,这类最费时但最确定
3. 做「改一行会怎样」的题 —— 想清楚那行管什么
4. 做「是否总是成立」的题 —— 找反例,先试 n=0、n=1、全相同、全负数
5. 最后回头看有没有空着的判断题,全部填上

⚠️ 前面的判断题往往是后面选择题的钥匙。

CSP 2022 第 17 题:单选题问「输入 100 100 时输出的第一行」,而那个朴素递归 f(100,100) 根本跑不出来(实测 20 2 就调用了一百多万次)。但判断题 (2) 告诉你「输出的两行总是相同」——用第二行的 DP 值 g(100,100) = 7 就能回答。

📝 做完判断题先别急着翻页,想想它们能不能用来算后面的。


30 秒自测

  1. 判断题一道多少分?空着划算吗?
  2. 拿到程序的第一件事该做什么?
  3. 看到「总是」「一定」,先试哪几种输入?
  4. 「函数返回值」和「程序输出」有什么区别?举个真题例子。
  5. 子串和子序列的区别是什么?
  6. for (; x; x &= x-1) ret++; 在算什么?
  7. 「递归写错了」一定会死循环吗?
  8. 前面的判断题对后面的选择题有什么用?
参考答案
  1. 1.5 分;只有两个选项,空着纯亏,必须填
  2. 读一遍判断它在算什么(对照模型表),然后画手动模拟表
  3. n=0n=0n=1n=1、全相同、全负数、边界值
  4. 返回值是函数 return 的那个数,输出是 cout 打的;CSP 2024 第 18 题里两者差一个平方
  5. 子串必须连续,子序列可以不连续
  6. x 二进制里 1 的个数(popcount)
  7. 不一定;CSP 2025 第 16 题的错误 gcd 实测正常终止
  8. 判断题的结论常常能直接用来推算选择题(如 CSP 2022 第 17 题)