CSP-J 2026 初赛试题解析(第二部分:阅读程序题(第一题))精讲



第一题:程序(1)------数字减半小精灵

一、先读懂程序:它在做什么?

这个程序的代码如下:

复制代码
#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;

    int x = 1, y = 1;

    while (n > 0) {
        if (n % 2 == 0) {
            ++x;
        } else {
            ++x;
            ++y;
        }

        n = n / 2;
    }

    cout << x << ' ' << y << endl;
    return 0;
}

对应试卷第16~21题。


1. 给程序编一个故事

想象有一个数字小精灵,它拿着一个正整数。

每次行动时,它都会:

  • 看看手里的数字是奇数还是偶数。

  • 不管奇数还是偶数,都会让 x 增加1。

  • 如果是奇数,还会让 y 增加1。

  • 最后,把手里的数字除以2,舍去小数部分。

如此反复,直到数字变成0。

最后,程序报告 xy 的值。


2. 认识三个重要角色

变量 初始值 作用
n 用户输入 当前正在处理的数字
x 1 每执行一轮循环就增加1
y 1 遇到奇数时增加1

这里要特别注意:

复制代码
n = n / 2;

因为 nint 类型,所以整数除法会舍去小数部分。

例如:

复制代码
7 / 2 = 3
6 / 2 = 3
3 / 2 = 1
1 / 2 = 0

因此,数字会逐渐变小,最终到达0。


二、第16题:输入3,输出是不是3 3?

原题:

当输入为3时,程序输出为3 3 。(判断题)


我们来模拟。

初始状态:

复制代码
n = 3
x = 1
y = 1

第1轮循环

此时 n = 3

判断:

复制代码
n % 2 == 0

3除以2余1,所以条件不成立,进入 else

执行:

复制代码
++x;
++y;

得到:

复制代码
x = 2
y = 2

接着:

复制代码
n = n / 2;

得到:

复制代码
n = 1

第2轮循环

现在 n = 1

1是奇数,所以再次执行:

复制代码
++x;
++y;

得到:

复制代码
x = 3
y = 3

然后:

复制代码
n = 1 / 2 = 0

循环结束

因为:

复制代码
while (n > 0)

此时 n = 0,条件不成立,循环结束。

输出:

复制代码
3 3

答案:√,正确。


侦探笔记

不要把 n = n / 2 忘记了!

如果漏掉这一行,程序中的 n 一直不变,循环就可能永远执行下去。


三、第17题:删除第11行的 ++x,两个数一定相等吗?

原题:

将第11行的 ++x; 删除后,程序输出的两个数一定相等。(判断题)


我们先看修改后的程序逻辑。

原来的代码:

复制代码
if (n % 2 == 0) {
    ++x;
} else {
    ++x;
    ++y;
}

删除 else 中的 ++x 后,相当于:

复制代码
if (n % 2 == 0) {
    ++x;
} else {
    ++y;
}

也就是说:

  • 遇到偶数,只有 x 增加。

  • 遇到奇数,只有 y 增加。

而且 xy 一开始都是1。

用输入3试一试

初始:

复制代码
x = 1
y = 1
n = 3

第一轮,3是奇数:

复制代码
x = 1
y = 2

n 变成1。

第二轮,1还是奇数:

复制代码
x = 1
y = 3

n 变成0,循环结束。

最终:

复制代码
x = 1
y = 3

显然不相等。

答案:×,错误。


侦探笔记

题目中出现"一定"两个字时,要特别小心。

如果要证明"一定相等",必须保证所有符合条件的输入都相等。

只要找到一个反例,就能推翻这个结论。


四、第18题:第一个数一定不小于第二个数吗?

原题:

假设输入为非负整数,则程序输出的第一个数一定不小于第二个数。(判断题)

程序没有修改,仍然是:

复制代码
if (n % 2 == 0) {
    ++x;
} else {
    ++x;
    ++y;
}

我们发现:

  • 每轮循环,x 都增加1。

  • 遇到奇数,y 也增加1。

  • 遇到偶数,y 不增加。

因此,x 增加的次数一定不少于 y 增加的次数。

又因为它们的初始值相同:

复制代码
x = 1
y = 1

所以最终:

复制代码
x >= y

即第一个数一定不小于第二个数。

答案:√,正确。


侦探笔记

这道题不必枚举所有输入。

只要比较两个变量每轮的变化规律,就可以直接得出结论。

这种方法叫作分析变量变化规律


五、第19题:把 while (n > 0) 改成 while (n >= 0) 会怎样?

原题:

将第7行的:

复制代码
while (n > 0)

改为:

复制代码
while (n >= 0)

程序可能出现的问题是:

A. 陷入死循环

B. 输出结果比原来大

C. 输出结果比原来小

D. 输出结果不受影响

1. 原来的循环有什么特点?

原来是:

复制代码
while (n > 0)

n 变成0时,条件不成立,循环结束。

2. 修改后呢?

现在变成:

复制代码
while (n >= 0)

n = 0 时:

复制代码
0 >= 0

条件仍然成立!

进入循环后:

复制代码
n = n / 2;

于是:

复制代码
0 / 2 = 0

下一轮还是0,再下一轮还是0......

复制代码
n = 0
n = 0
n = 0
n = 0
......

循环永远无法结束。


答案

A. 陷入死循环。


侦探笔记

循环题一定要问自己三个问题:

  1. 循环什么时候开始?

  2. 每轮循环变量如何变化?

  3. 变量变化后,能不能让循环条件最终变成假?

尤其要警惕:

复制代码
while (n >= 0)

如果 n 是非负整数,并且循环中不断进行 n = n / 2,那么它最终会停在0,而不是变成负数。


六、第20题:输入6,输出什么?

原题:

当输入为6时,输出为:

A. 3 3

B. 4 2

C. 4 3

D. 5 2


这次我们用一张表格追踪程序。

初始:

复制代码
n = 6
x = 1
y = 1

逐轮模拟

轮数 当前 n 奇偶性 x 的变化 y 的变化 执行除以2后 n
初始 6 --- 1 1 ---
第1轮 6 偶数 2 1 3
第2轮 3 奇数 3 2 1
第3轮 1 奇数 4 3 0

n = 0 时,循环结束。

最终:

复制代码
x = 4
y = 3

答案

C. 4 3。


七、第21题:有多少个输入会让第二个数恰好为2?

原题:

若输入 n 依次取遍:

复制代码
0, 1, 2, ..., 2^31 - 1

程序输出的第二个数恰好为2的次数为:

A. 16

B. 30

C. 31

D. 32

这道题稍微有一点数学味道,但我们把它拆开就很简单了。

1. 先看 y 是怎么变化的

程序开始时:

复制代码
int x = 1, y = 1;

所以:

复制代码
y = 1

只有当 n 是奇数时,才会执行:

复制代码
++y;

因此,想让最终的 y = 2,就必须满足:

整个循环过程中,恰好遇到一次奇数。


2. 用二进制观察

一个整数除以2时,整数部分相当于二进制数右移一位。

而:

复制代码
n % 2

恰好可以判断二进制数最右边的一位是0还是1。

例如:

复制代码
十进制 n = 6
二进制   = 110

依次除以2:

复制代码
6 → 3 → 1 → 0

对应二进制:

复制代码
110 → 11 → 1 → 0

每遇到一个奇数,就相当于发现一个二进制中的1。

所以,y 最终等于:

复制代码
1 + n 的二进制表示中1的个数

3. 什么时候 y = 2?

必须满足:

复制代码
二进制中恰好有一个1

这样的数就是:

复制代码
1
10
100
1000
10000
......

也就是十进制的:

复制代码
1、2、4、8、16、32、......

这些数都是2的整数次幂。


4. 统计有多少个

题目给出的范围是:

复制代码
0 ≤ n ≤ 2^31 - 1

符合条件的数为:

复制代码
2^0, 2^1, 2^2, ..., 2^30

从指数0到指数30,一共有:

复制代码
30 - 0 + 1 = 31

个。

注意,2^31 已经超过题目给出的最大值,不能计算进去。


答案

C. 31。


第一题总结

题号 考查内容 答案
16 循环模拟
17 变量变化规律、反例 ×
18 循环中变量的变化关系
19 循环边界、死循环 A
20 循环模拟 C
21 二进制与奇偶性 C

第一题通关!


相关推荐
syagain_zsx1 小时前
算法基础篇 · 04 前缀和(C++ 题解)
c++·算法·前缀和
汉克老师2 小时前
CSP-J 2026 初赛试题解析(第三部分:完善程序题(第一题))精讲
c++·csp-j·小学生·学c++编程
haluhalu.3 小时前
初识 Protobuf:微服务跨语言通信的一份契约
java·c语言·开发语言·c++·python
longxuan013 小时前
倍增算法详解
c++·st表·倍增算法
-森屿安年-3 小时前
返回最大数
c++·贪心算法
0+1113 小时前
算法 --二分查找
c++·算法·leetcode
拂拉氏3 小时前
【项目实现】 C++ vector实现(空间配置器+异常处理)
c++·vector·异常·空间配置器
qq_199886874 小时前
第8板块·第3节:设备间拷贝与点对点(P2P)传输
c++·人工智能·gpu算力·cuda
爱奥尼欧4 小时前
【C++】map、set 的底层是什么?红黑树五条性质、插入旋转到模拟实现
开发语言·数据结构·c++