CSP-S 2026 初赛试题解析(第二部分:阅读程序题(第一题))精讲
2026/9/24 16:33:18 网站建设 项目流程



2026 CSP-S 第一轮真题

第二部分·阅读程序第 1 题:《二进制除法》

答案是:

16:对✅️,17:对✅️,18:错❌️;19:C,20:B,21:C。


一、先认识题目中的“二进制除法”

程序中有一个数组:

int gen[13] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1};

它一共有 13 个元素:

下标: 0 1 2 3 4 5 6 7 8 9 10 11 12 gen: 1 1 0 0 0 0 0 0 0 1 1 1 1

连起来就是:

1100000001111

题目程序把输入的 32 位二进制字符串放进数组a,然后用gen进行一系列异或操作,最后输出a[32]a[43]

我们先记住两个重要知识:

  1. 异或^:两个相同的二进制位异或得到 0,不同得到 1。

  2. 模 2 除法:在二进制多项式除法中,减法可以用异或来完成,不需要借位。


二、逐段理解程序

1. 读入 32 位二进制字符串

cin >> s; for (int i = 0; i < 32; ++i) { a[i] = s[i] - '0'; }

假设输入:

100100...

cin >> s把整个字符串读入s

接着:

a[i] = s[i] - '0';

把字符'0''1'转换成整数01

例如:

字符s[i] - '0'存入数组
'0'0a[i] = 0
'1'1a[i] = 1

所以,数组a[0]a[31]保存输入的 32 个二进制位。


2. 给后面的 12 位补零

for (int i = 32; i < 44; ++i) { a[i] = 0; }

循环让:

a[32], a[33], ..., a[43]

全部变成 0。

一共是:

44−32=12

也就是在原来的 32 位二进制串后面补上 12 个 0。

为什么补 12 个?

因为gen有 13 位,而它的最高位对应a[i],所以当程序处理到a[31]时,仍然需要访问:

a[31 + 12]

也就是:

a[43]

因此数组必须准备到下标 43。


3. 关键循环:异或消除

for (int i = 0; i < 32; ++i) { if (a[i] == 0) continue; for (int j = 0; j < 13; ++j) { a[i + j] ^= gen[j]; } }

这是整道题的核心。

我们先把异或的规则记住:

左边右边异或结果
000
011
101
110

特别要记住:

所以,两个相同的位异或后会变成 0。

if (a[i] == 0) continue;是什么意思?

如果当前位a[i]是 0,就直接跳过本轮循环,不做后面的异或操作。

如果a[i]是 1,就把gen的 13 个二进制位依次与:

a[i], a[i+1], ..., a[i+12]

进行异或。

由于gen[0] == 1,所以第一步一定会执行:

a[i] ^= 1;

a[i]原本是 1 时:

于是当前位就被消除了。

这和二进制长除法的思路非常相似:发现当前位是 1,就把除数对齐到这一位,用异或进行消除。


三、判断题 16:输入 32 个 0,输出是不是 12 个 0?

题目说:

当输入为 32 个'0'时,程序输出 12 个 0。

我们来验证。

如果输入全是 0:

00000000000000000000000000000000

那么:

a[0] = 0; a[1] = 0; ... a[31] = 0;

补零后:

a[32] = 0; ... a[43] = 0;

接下来进入主循环:

for (int i = 0; i < 32; ++i) { if (a[i] == 0) continue; ... }

因为每个a[i]都是 0,所以每次都会执行:

continue;

也就是说,内层异或循环一次都不会执行。

最后输出:

for (int i = 32; i < 44; ++i) { cout << a[i]; }

输出的就是:

000000000000

因此,判断题 16:

对(√)


四、判断题 17:结束后a[0]a[31]一定全为 0 吗?

题目说:

程序运行结束后,数组a中下标从 0 到 31 的元素一定全部为 0。

答案是:对。


为什么?

程序从左向右处理:

for (int i = 0; i < 32; ++i)

对于每个位置i

  • 如果a[i] == 0,就跳过;

  • 如果a[i] == 1,就用gen异或消除它。

因为gen[0] == 1,所以当a[i] == 1时,第一位会变成:

1⊕1=01\oplus1=0

而内层循环只会修改:

a[i], a[i+1], ..., a[i+12]

不会修改比i更靠前的位置。

因此,已经处理完的位置不会再被后面的循环改变。

可以把它想象成一排灯泡:

  • 从左向右检查;

  • 遇到亮着的灯泡,就执行一次操作把它熄灭;

  • 后面的操作不会再碰已经检查过的左边灯泡。

最终:

a[0] = 0 a[1] = 0 ... a[31] = 0

所以判断题 17:

对(√)


五、判断题 18:删除补零循环,会改变输出吗?

题目说:

若将第 12~14 行(为a[32]a[43]补 0 的循环)删除,会改变程序输出结果。

答案是:错。


这题有一个非常重要的 C++ 知识点。

程序中:

int a[100];

这里的a是定义在函数外面的全局数组

在 C++ 中,全局变量如果没有显式初始化,会自动进行零初始化。

也就是说,即使删除:

for (int i = 32; i < 44; ++i) { a[i] = 0; }

数组a[32]a[43]仍然会自动是 0。

因此,这个补零循环实际上是重复做了一次已经自动完成的事情。

删除它不会改变程序的输出。

所以判断题 18:

错(×)


记忆小卡片

  • 全局数组:没有显式初始化时,元素会自动初始化为 0。

  • 普通局部数组:没有显式初始化时,元素的值通常是不确定的,不能直接当成 0 使用。


六、单选题 19:gen数组表示什么?

题目问:

关于第 6 行定义的数组gen,下列说法正确的是哪一个?

选项:

  • A.gen共有 12 个元素,表示一个 12 位的除数

  • B.gen共有 13 个元素,表示一个 13 位的被除数

  • C.gen共有 13 个元素,其中gen[0]是除数的最高位

  • D.gen共有 13 个元素,其中gen[12]是除数的最高位

首先,数一数:

int gen[13] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1};

数组有 13 个元素,下标是:

0 到 12

对应的二进制串是:

1100000001111

程序把gen[0]a[i]对齐,然后把gen[1]a[i+1]对齐,依此类推。

所以gen[0]对应二进制串最左边的位,也就是最高位。

因此正确选项是:

C


七、单选题 20:程序实现了什么功能?

题目问:

该程序实现的功能,最准确的说法是哪个?

选项 B 的意思是:

将输入串视为 32 位二进制数 MM,在其后补 12 个 0,也就是计算 M×212M\times2^{12},再对它用1100000001111作模 2 除法求余数,并输出 12 位余数。


我们前面已经分析了:

  1. 输入的 32 位串被存入数组;

  2. 后面补 12 个 0;

  3. 从左向右处理每一位;

  4. 当前位为 1 时,将除数对齐并异或;

  5. 最后输出下标 32 到 43 的 12 位结果。

这正是二进制模 2 长除法的过程。

因此,正确选项是:

B


为什么输出是 12 位?

除数是 13 位二进制数。

在普通长除法中,余数的位数小于除数的位数;这里除数是 13 位,所以余数最多是 12 位。

程序输出:

for (int i = 32; i < 44; ++i) cout << a[i];

刚好输出 12 位。


八、单选题 21:删除continue后会发生什么?

题目问:

若将第 16 行if (a[i] == 0) continue;删除,说法正确的是哪一个?

选项:

  • A. 程序的结果不会改变

  • B. 可能造成程序运行错误

  • C. 程序能够正常输出一个 12 位'0'/'1'串,但是输出结果与输入的s无关

  • D. 程序运行结束后,a[0]的值一定为 0


正确选项是:

C

我们来仔细理解。


1. 原来有continue

if (a[i] == 0) continue;

如果当前位是 0,就跳过异或。

只有当前位为 1 时,才执行内层循环。

所以程序会根据输入的二进制串进行不同的操作。


2. 删除continue

程序变成:

for (int i = 0; i < 32; ++i) { for (int j = 0; j < 13; ++j) { a[i + j] ^= gen[j]; } }

这时,无论a[i]是 0 还是 1,都会执行异或。

而且循环次数完全固定:

  • i一定从 0 到 31;

  • j一定从 0 到 12;

  • 每次都使用同一个固定的gen

因此,程序对数组执行的操作序列不再取决于输入字符串s

虽然数组最初的前 32 位可能不同,但每次异或操作都按固定顺序执行,最终输出也会变成一个固定的 12 位串。

所以:

  • 程序仍然可以正常输出;

  • 输出长度仍然是 12 位;

  • 输出结果与输入的s无关。

因此,正确答案是C


九、第一题的六道小题答案汇总

题号正确答案核心原因
16输入全 0,所有位都跳过异或,输出 12 个 0
17从左向右消除,每个处理过的位置最终为 0
18×全局数组会自动零初始化,删除补零循环不影响输出
19Cgen有 13 个元素,gen[0]是最高位
20B补 12 个 0 后进行模 2 除法,输出 12 位余数
21C删除continue后操作固定,输出不再依赖输入串

十、给同学们的三个重要知识点

知识点 1:异或可以用于二进制模 2 除法

a[i + j] ^= gen[j];

异或的特点是:

0 ^ 0 = 0 0 ^ 1 = 1 1 ^ 0 = 1 1 ^ 1 = 0

特别是1 ^ 1 = 0,它可以用来消除当前位。


知识点 2:continue会跳过本轮循环剩余部分

if (a[i] == 0) continue;

当条件成立时,程序直接进入下一轮i循环,后面的内层循环就不会执行。


知识点 3:全局数组会自动初始化

int a[100];

如果它是全局数组,没有显式初始化时,元素会自动变成 0。

这也是判断题 18 的关键。


这道题最核心的程序思想可以概括为:从左向右扫描二进制串,遇到 1 就用异或消除,最后留下 12 位余数。


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询