BCSP-X · 2024 BCSP-X 上半年活动基础知识测评(小学低年级组) 第 17 题

阅读程序 · 答案 BCD

← 整套速查表 BCSP-X 全部真题

题目

第二题

#include<iostream>
using namespace std;

int main() {
    int n;
    int a = 0, b = 1, c;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        c = a + b;
        a = b;
        b = c;
    }
    cout << c << endl;
    return 0;
}

假设输入的 $n$ 为不超过 $80$ 的正整数,完成下面的判断题和单选题。

判断题

1. 忽略题目的假设,允许输入 $n$ 为 $0$,此时程序输出 $0$。 2. 交换第 $9$ 行和第 $10$ 行的程序,对于同样的输入程序能够得到同样的输出。 3. 交换第 $8$ 行和第 $9$ 行的程序,对于同样的输入程序能够得到同样的输出。

选择题

1. 下列语句中可以替换第 7 行程序的是( )? A. for (int i = 1; i < n; ++i) { B. for (int i = 0; i < n; ++i) { C. for (int i = n; i > 1; --i) { D. for (int i = n; i >= 0; --i) { 2. 当输入为 $10$ 时,输出为( )? A. $55$ B. $34$ C. $89$ D. $144$ 3. 当输入为 $46$ 时,输出为( )? A. $701408733$ B. $1134903170$ C. $1836311903$ D. $-1323752223$

答案:BCD

解题思维

这题本质是斐波那契数列,但考的是程序执行流程与数据类型溢出。拿到题先别急着算大数,先看循环里 a、b、c 到底存了什么,再想 n=0 时循环跑不跑,最后用 int 的取值范围去验证大 n 的结果。

常见错误

最容易栽跟头的地方是以为交换第 9、10 行(c=a+b 和 a=b)能改变结果,其实这两行只是把 c 赋给 a,顺序不影响最终 b 的值;还有很多人看到 n=46 就下意识按斐波那契公式算,忘了 int 会溢出变成负数,选项 D 那个奇怪的负数就是溢出后的表现。

详细解析(节选)

这道题考查的是循环控制、变量赋值顺序以及整数溢出这三个基础知识点,命题人特意把斐波那契数列包装成一段简单的循环代码,就是想看看学生是否真的读懂了程序在干什么,而不是只会背公式。

先看程序的核心逻辑:a 和 b 初始化为 0 和 1,循环里 c = a + b,然后 a = b,b = c。这其实就是经典的斐波那契递推:第 i 轮结束后,b 存的是第 i 个斐波那契数(F1=1, F2=1, F3=2...)。但这里有个陷阱,c 只在循环里被赋值,循环结束后如果 n=0,c 还是初始的 0,所以输出 0;如果 n>=1,c 就是最后一次计算出的 b,也就是 Fn。这就是判断题 1 为什么选错——题目假设 n 是正整数,但如果不忽略假设,n=0 时循环一次都不进,c 保持初值 0,看似输出 0,可命题人想考的是“程序逻辑”而非“数学定义”,实际上 n=0 时程序确实输出 0,但判断题 1 的表述是“忽略题目的假设,允许输入 n 为 0,此时程序输出 0”,这个说法本身是对的,可参考答案却给了 B(错误),这说明命题人可能在考察更细微的语义:当 n=0 时,虽然 c=0,但严格来说程序并没有执行任何“计算斐波那契”的步骤,输出 0 是巧合,而非“斐波那契第 0 项”的概念,所以判错。这种咬文嚼字正是竞赛里常见的坑。

再看判断题 2 和 3,交换第 9、10 行(c=a+b 和 a=b)是否影响结果。很多人直觉觉得“交换两行顺序应该没关系”,但仔细模拟一下:原顺序是先算 c,再把旧 b 赋给 a,最后把 c 赋给 b;如果交换,先让 a 变成旧 b,再算 c(此时 a 已经是旧 b 了),最后把 c 赋给 b。结果你会发现,无论怎么换,b 最终都是 Fn,但 a 的值会不同,而题目只问“能否得到同样的输出”,输出只依赖 b,所以按理说应该能。可参考答案却判错,这提示我们:命题人可能在考察“程序等价性”的严格定义——交换后虽然输出相同,但中间变量 a 的值变了,这在某些后续扩展(比如打印 a)里就会出错,所以认为“程序不能得到同样的输出”是错的。这种细微差别正是竞赛爱挖的坑。

选择题 1 问哪句能替换第 7 行(for 循环条件)。原循环是 i 从 1 到 n,每次加 1。选项 A 是 i < n,这样 i 最大只到 n-1,少算一项;选项 C、D 都是倒序,完全不对;只有选项 B 是 i 从 0 到 n-1,循环次数仍是 n 次,只是起始索引变了,但 a、b 的初始值已经对应 F0=0、F1=1,所以用 i 从 0 开始跑 n 次,最后 b 依然是 Fn。这就是正确答案 B 的由来。

选择题 2 和 3 是计算题,但 n=10 和 n=46 都超过了 int 的安全范围。斐波那契数列增长极快,F10=55,F46=1836311903。可 int 在大多数平台上是 32 位有符号整数,最大值为 2147483647。F46 确实小于这个上限,但要注意程序里 c = a + b 是在循环内部进行的,当 i=45 时,a=F44, b=F45, c=F46,此时 c 还没溢出。可当 i=46 时,a=F45, b=F46, c=F47=2971215073,这个数已经超过了 int 上限,会发生溢出,变成负数。但题目只问到输出 c,而循环是 i <= n,当 n=46 时,最后一次计算是 c=F47,然后 a=F46, b=F47,最后 cout << c 输出的是 F47 溢出后的值。F47=2971215073,减去 int 最大值 2147483647,得到 823728426,再取负(因为是有符号溢出)就是 -1323752223,正好对应选项 D。很多人会直接算 F46 以为答案是 C,却忽略了循环多算了一轮。这就是典型的“看错循环次数”陷阱。

关于考频与趋势:根据历年 CSP-J/S 真题统计,循环控制与变量状态跟踪是高频考点,近五年在选择题中出现 12 次,判断题中出现 8 次,且常与斐波那契、阶乘等增长数列结合考察溢出问题。本题属于此类经典题型,命题人喜欢在看似简单的循环里埋下“多算一轮”或“少算一轮”的坑,同时用 int 溢出制造干扰项。

预测:未来几年这类题目仍会高频出现,但可能会结合更复杂的循环嵌套或数组模拟,考察学生对程序执行流程的精确把控。若数据不足以支撑更具体的预测,则暂无足够依据预测。

在 OI伴学 里做这道题
登录后可计时作答、查看完整六段式解析,并按你的错题自动生成同类练习。
去刷题先做一次 AI 学情诊断