试卷解析 · 理解每一步
提高组 CSP-S 2026 初赛模拟卷 2
CSPS-2026-R1-Mock-2
试卷解析总览,可直接查看每题答案与解析。
第 1 题(单选题,2 分)
大多数计算机病毒主要造成计算机()的损坏。
正确答案A
解析详情
病毒本身就是一种程序,所以破坏的主要是软件和数据。
第 2 题(单选题,2 分)
假设有253块月饼,把它们装到15个盒子里面,那么数量最多的一盒至少装( )块月饼。
正确答案D
解析详情
鸽巢原理也叫抽屉原理,m 个物体放到 n 个抽屉里至少有一个抽屉有 个物体,所以 。
第 3 题(单选题,2 分)
ASCII 码是由美国国家标准委员会指定的一种包括数字、字母、通用字符和控制符号在内的字符编码集,它是一种( )位二进制码。
正确答案B
解析详情
ASCII 是一种 7 位的二进制编码,能表示 种国际通用的西文字符,是目前计算机中,尤其是微型计算机中使用最普遍的字符编码集。注意 char 类型占据一字节,也就是 8 位二进制,但有效的基本 ASCII 码只占据 7 位。注意在有些非英语语言中,会用超过 7 位的码表示其他符号,但这不属于标准 ASCII 码。
第 4 题(单选题,2 分)
计算机的硬件主要包括控制器、( )、存储器、输入设备、输出设备。
正确答案A
解析详情
运算器是计算机的主要硬件之一,主要进行各种算术运算和逻辑运算。操作系统是软件,计算机语言是软件程序的载体,磁盘是存储器的一种具体形式。
第 5 题(单选题,2 分)
字符 'a' 的 ASCII 码是 97,下面程序的输出结果是( )。
char c = 'a' + 4;
cout << c << ", " << (int) c + 3 << endl;正确答案C
解析详情
char c = 'a' + 4;,c 保存的是字符 'e'。(int) c 是将字符 'e' 转成整数类型 ASCII 码,即 101。101 + 3 = 104。
第 6 题(单选题,2 分)
操作系统是对( )进行管理的软件。
正确答案A
解析详情
操作系统管理的内容涵盖硬件资源(如 CPU、内存)和软件资源(如文件、进程、应用程序)。
第 7 题(单选题,2 分)
以下选项中,( )不是操作系统。
正确答案D
解析详情
Celeron 是指处理器而非操作系统环境。
第 8 题(单选题,2 分)
以下关于 C++ 语言注释的说法中正确的是()。
正确答案D
解析详情
写 C++ 程序时可写注释,也可不写,注释只起注解说明的作用,不会参与编译、运行过程。“/* */”用于注释代码块,已经注释的内容不能再次被注释,即不允许嵌套,所以“C++ 注释内容可以是任何字符”是错误的。例如不能嵌套写“/*/*/* /”。
第 9 题(单选题,2 分)
要使用 putchar 函数实现向显示器输出字符 'A',可使用()。
正确答案A
解析详情
putchar 函数的作用是向显示终端输出一个字符,一般形式为 putchar(c),其中参数 c 为 int,输出的字符是 c 值对应的 ASCII 码。选项 B、D 的传参类型不对,语法错误;选项 C 可以通过编译,实际是将 '\\65' 强转为 int 插入,但注意这里 \\65 是以八进制算的,所以实际上是 ASCII 码 57,对应字符 '5'。这里写 putchar('A') 或 putchar('\\101') 也是对的。
第 10 题(单选题,2 分)
两个指针类型变量()。
正确答案D
解析详情
如果两个指针指向同一个数组中的元素,则可以相减(其实是底层重载操作符的结果),其值为两个指针之间的元素个数,但指针之间不能直接相加(不过指针加常数是可以的)。某时刻两个指针同时指向了一个变量,不影响之后改变其值使其指向其他变量。指针之间可以比较是否相等(指向同一内存地址)。
第 11 题(单选题,2 分)
下列属于 B 类 IP 地址的是( )。
正确答案C
解析详情
B 类 IP 地址的范围是 128.0.0.0~191.255.255.255,也就是以二进制 10 开头。选项 B 中
的值300超过255;选项A、D的第一项不在B类地址范围内。
第 12 题(单选题,2 分)
现有变量 a, b, c, d,取值范围均为 [0,15],假设每个值出现的概率相同,则 a ^ b ^ c ^ d 的值能被 3 整除的概率是( )。(这里 ^ 为按位异或运算符。)
正确答案A
解析详情
以二进制看,取值为所有4位二进制数,被3整除只有6种可能:0000, 0011, 0110, 0101, 1100, 1111。由异或的性质,每一位等于0或1的概率都是1/2,所以结果是任意一种的概率都是1/16,总概率为6/16=3/8。
第 13 题(单选题,2 分)
假设以 S 和 X 分别表示进栈和出栈操作,对输入序列 a, b, c, d, e 进行一系列栈操作 SSXSXSSXXX 之后,得到的输出序列为()。
正确答案B
解析详情
a 入栈,b 入栈,b 出栈,c 入栈,c 出栈,d 入栈,e 入栈,e 出栈,d 出栈,a 出栈。
第 14 题(单选题,2 分)
某递归算法的执行时间的递推关系如下:当 n = 1 时 ,当 n > 1 时 。则该算法的时间复杂度为()。
正确答案C
解析详情
最简单的做法是直接代入数值计算,如 ,直接找规律得到 。或利用主定理结论。
第 15 题(单选题,2 分)
一棵完全二叉树中有 501 个叶节点,则整棵树至少有( )个节点。
正确答案C
解析详情
二叉树恒等式: ,这里 ,则 。而对完全二叉树, 或 1,所以最少有 个节点。
二、阅读程序(1)
#include <iostream>
using namespace std;
const int maxn = 100001;
int N, M, K, x[maxn], y[maxn], d[maxn], c[maxn];
int *a[maxn];
int main() {
cin >> N >> M >> K;
for (int i = 0; i < K; ++i) {
// 表示第 x[i] 行第 y[i] 列值为 d[i]
cin >> x[i] >> y[i] >> d[i];
c[y[i]]++;
}
for (int i = 1; i <= M; ++i) a[i] = new int[c[i]];
for (int i = 0; i < K; ++i) {
*a[y[i]] = d[i];
a[y[i]]++;
}
for (int i = 1; i <= M; ++i) {
a[i] = a[i] - c[i];
for (int j = 0; j < c[i]; ++j, ++a[i])
cout << *a[i] << " ";
}
return 0;
}第 16 题(判断题,2 分)
程序定义了一个指针数组 a, a[i] 表示第 i 列的指针。 ()
正确答案正确
解析详情
根据代码中的注释,y 表示列数,而 a[y[i]]++ 表示 a[i] 是关联第 i 列的。
第 17 题(判断题,2 分)
将 改成 不影响运算结果。 ( )
正确答案正确
解析详情
允许将数组指针直接当作数组名使用。指针变量本身相当于数组的 0 号位置。
第 18 题(判断题,2 分)
第12行中,数组 c 用来统计每行中的数据个数。 ()
正确答案错误
解析详情
c 统计每列的数据个数。
第 19 题(判断题,2 分)
在本程序中,采用动态数组以优化空间的利用,每一列数组长度可能不同。 ()
正确答案正确
解析详情
本题中,N × M 可能会很大,直接用二维数组可能存储不下,因而采用了动态数组和指针,根据每一列的实际数据个数来申请该列的空间,使每列的“数组”长度不同。也可以使用 C++ 的 vector 容器,或者链式前向星结构实现同样效果。
第 20 题(单选题,3 分)
该程序的时间复杂度为()。
正确答案B
解析详情
根据各循环范围很容易看出是 ,N 没有用到过。
第 21 题(单选题,3 分)
该程序的空间复杂度为()。
正确答案A
解析详情
x, y, d 数组都是 K 的维度,a 数组本身(指针个数)是 M,而 a 动态申请的空间是 c[i] 的总和,也就是 K,所以最后是 M+K。另外也可以利用排除法,任何程序的空间复杂度都不会高于时间复杂度,排除 B 和 D,而 N 根本就没有用到过。
二、阅读程序(2)
#include <iostream>
#include <iomanip>
using namespace std;
int m[101][101];
int main() {
int a;
cin >> a;
int c = a * a, i = 1, k = (a + 1) / 2;
for (int j = 1; j <= c; j++) {
m[i][k] = j;
if (j % a == 0) {
if (i == a) i = 1; else i++;
} else {
if (i == 1) i = a; else i--;
if (k == a) k = 1; else k++;
}
}
for (int i = 1; i <= a; i++) {
for (int j = 1; j <= a; j++)
cout << setw(5) << m[i][j];
cout << endl;
}
return 0;
}第 22 题(判断题,2 分)
从程序可以看出,i 为被填数,j 和 k 为填数位置。 ()
正确答案错误
解析详情
j 为被填数。
第 23 题(判断题,2 分)
填数结束后,数组 m 中的元素互不相同。 ()
正确答案正确
解析详情
因为 j 一直在变大,且每次 j 循环里只会赋值到 m 一次,所以不可能出现重复。
第 24 题(单选题,3 分)
当 且 时,下一步填入的是()。
正确答案B
解析详情
符合这两个条件,执行 ,所以是 ,逻辑上为填完一斜线,进入下一条斜线。
第 25 题(单选题,3 分)
当 、 且 k == a 时,下一步填入的是()。
正确答案B
解析详情
此时执行了 i--;和 k=1;,所以是 m[i-1][1],逻辑为走到最右侧后回到最左侧。
第 26 题(单选题,4 分)
填数后,每行每列及对角线的和均为()。
正确答案A
解析详情
知道是幻方的话,用总和除以 a 即可: 。看不出的话,代入一个 a=2 验证就行了。
二、阅读程序(3)
#include <iostream>
using namespace std;
int a[101], d[101];
int main() {
int n = 5;
a[1] = d[1] = 1;
for (int i = 1; i <= n; ++i) {
int s = i + 1, x = 0;
for (int j = 1; j <= n + 1 - i; ++j) {
int k = s + x;
x++;
a[j + 1] = a[j] + k;
cout << a[j] << ' ';
}
cout << "..." << endl;
a[1] = d[i + 1] = d[i] + i;
}
return 0;
}第 27 题(判断题,2 分)
该题由两重循环构成,外循环 i 控制列的变化,内循环 j 控制行的变化。 ( )
正确答案错误
解析详情
按输出是先行后列的顺序,外循环 i 控制行的变化,内循环 j 控制列的变化。
第 28 题(判断题,2 分)
代码运行结果如下。
1 3 6 10 15
2 5 9 14
4 8 13
7 12
11正确答案错误
解析详情
输出的值是正确的,但少了“...”。
第 29 题(单选题,4 分)
程序在输出时,第 i 行为( )个 a[j] 数组的值。
正确答案A
解析详情
根据循环 j 的范围即可得知。
第 30 题(单选题,4 分)
本题代码的运算结果是输出()行。
正确答案B
解析详情
根据 n=5 及循环 i 的范围。
三、完善程序(1)
形如 的素数称为梅森素数。若 是梅森素数,则 P 一定也是素数。但反过来不一定,即如果 P 是素数, 不一定也是素数。到 1998 年年底,人们已找到了 37 个梅森素数。最大的一个是 ,即 P=3021377,它有 909526 位。梅森素数有许多重要应用,它与完全数密切相关。
你的任务:输入 P,计算 的位数及其最后 500 位数字(用十进制高精度数表示)。
输入数据:只包含一个整数 P(1000 < P < 3100000)。
输出要求: 第1行输出十进制高精度数 的位数, 第2~11行输出十进制高精度数 的最后500位数字(每行输出50位, 共输出10行, 不足500位时高位补0)。
#include <cstdio>
#include <memory>
#include <cmath>
#define LEN 125
void Multiply(int *a, int *b) {
int i, j, nCarry, nTmp, c[LEN];
memset(c, 0, sizeof(int) * LEN);
for (i = 0; i < LEN; i++) {
nCarry = 0;
for (j = 0; ①; j++) {
nTmp = c[i + j] + a[j] * b[i] + nCarry;
c[i + j] = nTmp % 10000;
nCarry = nTmp / 10000;
}
}
memcpy(a, c, LEN * sizeof(int));
}
int main() {
int i, p, anPow[LEN], aResult[LEN];
scanf("%d", &p);
printf("%d
", (int)(p * log10(2)) + 1);
anPow[0] = 2;
aResult[0] = 1;
for (i = 1; i < LEN; i++) {
anPow[i] = 0;
aResult[i] = 0;
}
while (②) {
if (③) {
Multiply(aResult, anPow);
}
p >>= 1;
Multiply(anPow, anPow);
}
aResult[0]--;
for (i = LEN - 1; i >= 0; i--) {
if (④)
printf("%02d
%02d", aResult[i] / 100, aResult[i] % 100);
else {
printf("%04d", aResult[i]);
if (i % 25 == 0) printf("
");
}
}
return 0;
}第 31 题(单选题,3 分)
①处应填()。
j < LENj < LEN - i - 1i < LEN - ij < 1正确答案C
解析详情
j 只要算到 LEN-i-1,是因为结果要加到 c[i+j] 上,避免 i+j 越界。
第 32 题(单选题,3 分)
②处应填()。
p > 0p == 0p < 0p >= 0正确答案A
解析详情
此处快速幂实现对 p 从低位开始的二进制拆分,直到 p=0 说明 p 中的有效位都用过了。
第 33 题(单选题,3 分)
③处应填()。
p & 1pp || 1p = 0正确答案A
解析详情
判断 p 当前的最低位是否为 1,如果为 1 则 apow 要乘到结果上去。
第 34 题(单选题,3 分)
④处应填()。
i != 0i > 0i % 10 == 0i % 25 == 12正确答案D
解析详情
输出从万进制数的第124位开始,万进制数的每一位输出为十进制数的4位,每行只能输出50个十进制位,所以发现当i%25==12时,第i个万进制位会被折行输出,其对应的后两个十进制位会跑到下一行。
三、完善程序(2)
在遥远的国家佛罗布尼亚,嫌犯是否有罪须由陪审团决定。陪审团是由法官从公众中挑选的。先随机挑选 n 个人作为陪审团的候选人,然后再从这 n 个人中选出 m 个人组成陪审团。选出 m 个人的方法:控方和辩方根据对候选人的喜欢程度,给所有候选人打分,分值从 0 到 20。为公平起见,法官选出陪审团的原则是选出的 m 个人,必须满足辩方总分和控方总分的差的绝对值最小。如果有多种选择方案的辩方总分和控方总分之差的绝对值相同,那么选辩控双
方总分之和最大的方案即可。最终选出的方案称为陪审团方案。
输入数据:输入包含多组数据。每组数据的第一行是两个整数 n 和 m,n 是候选人数目,m 是陪审团人数。 , ,而且 m n。接下来 n 行每行表示一个候选人的信息,它包含两个整数,分别是控方和辩方对该候选人的打分。候选人按出现的先后从 1 开始编号。两组有效数据之间以空行分隔。最后一组数据 n = m = 0。
输出要求:对每组数据,先输出一行,表示答案所属的组号,如 Jury #1、Jury #2 等。接下来的一行输出陪审团的控方总分和辩方总分。再下来一行要以升序输出陪审团里每个成员的编号,两个成员编号之间用空格分隔。每组输出数据须以一个空行结束。
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <algorithm>
int f[30][1000], Path[300][1000];
int P[300], D[300], Answer[30];
int main() {
int i, j, k, t1, t2, n, m, nMinPD;
int nCaseNo = 0;
scanf("%d%d", &n, &m);
while (n + m) {
nCaseNo++;
for (i = 1; i <= n; i++) scanf("%d%d", &P[i], &D[i]);
memset(f, -1, sizeof(f));
memset(Path, 0, sizeof(Path));
nMinPD = ①;
②;
for (j = 0; j < m; j++) {
for (k = 0; ③; k++)
if (④) {
for (i = 1; i <= n; i++)
if (⑤) {
t1 = j; t2 = k;
while (t1 > 0 && Path[t1][t2] != i) {
t2 -= P[Path[t1][t2]] - D[Path[t1][t2]];
t1--;
}
if (t1 == 0) {
f[j + 1][k + P[i] - D[i]] = f[j][k] + P[i] + D[i];
Path[j + 1][k + P[i] - D[i]] = i;
}
}
}
}
i = nMinPD; j = 0;
while (f[m][i + j] < 0 && f[m][i - j] < 0) j++;
if (f[m][i + j] > f[m][i - j]) k = i + j;
else k = i - j;
printf("Jury #%d
", nCaseNo);
printf("Best jury has value %d for prosecution and value %d for defence:
",
(k - nMinPD + f[m][k]) / 2, (f[m][k] - k + nMinPD) / 2);
for (j = 1; j <= m; j++) {
⑥;
k -= P[Answer[j]] - D[Answer[j]];
}
std::sort(Answer + 1, Answer + m + 1);
for (i = 1; i <= m; i++) printf("%d ", Answer[i]);
printf("
");
scanf("%d%d", &n, &m);
}
return 0;
}第 35 题(单选题,3 分)
① 对应填()。
nMinPD = m*20nMinPD = mnMinPD = m*200nMinPD = m*n正确答案A
解析详情
nMinPD 表示能实现的总分之差的最小值,初始时应为足够大的数。因为每个人的最高分为 20,共选 m 个人,所以差值不会超过 m*20。C 选项值更大,理论上作为初始值没有问题,但后面 nMinPD 要被作为 f 的第二维下标(见空②),而这个维度只开到 1000,所以不能超过这个上限,而 m*200 最大是 4000,所以不行。
第 36 题(单选题,3 分)
②处应填( )。
f[0] [nMinPD] = 1f[0] [nMinPD] = 0f[0] [nMinPD] > 0f[0] [nMinPD] > 1正确答案B
解析详情
选项 C 和 D 显然无意义。f[0][nMinPD] 表示选 0 个人,这时候显然总分之和为 0。注意,因为分差可能为负,而下标不允许为负,这里做了一下下标平移,平移量就是 nMinPD,所以代码里的 f[0][nMinPD] 逻辑上是表示 f[0,0] 的。
第 37 题(单选题,3 分)
③处应填( )。
k < nMinPD*2k < nMinPDk <= nMinPD*2k <= nMinPD正确答案C
解析详情
分差的范围上限是 nMinPD,加上平移量,所以最大值为选项 C。
第 38 题(单选题,3 分)
④处应填()。
f[j][k] > 1f[j][k] >= 1f[j][k] >= 0f[j][k] > 0正确答案C
解析详情
初始化的时候用 表示做不到,所以只有 才能往后转移。
第 39 题(单选题,3 分)
⑤ 处应填()。
f[j][k] + P[i] + D[i] > f[j + 1][k + P[i] - D[i]]f[j][k] + P[i] + D[i] > f[j + 1][k + P[i]]f[j][k] + P[i] > f[j + 1][k + P[i]]f[j][k] + P[i] > f[j + 1][k + P[i] - D[i]]正确答案A
解析详情
转移条件是选 i 更优,维度 2 是分差,所以要加上 P-D。值是分和,所以要加上 P+D。
第 40 题(单选题,3 分)
⑥ 处应填()。
Answer[j] = Path[m-j][k]Answer[j] = Path[m-j][k+1]Answer[j] = Path[m-j+1][k+1]Answer[j] = Path[m-j+1][k]正确答案D
解析详情
Path[j,k] 记录对 f[j,k] 取到最优解时,所选的最后那个人。最后求方案时要从 j=m 倒着推,所以第一维是 m-j+1。从前面对 k 的赋值看,k 表示分差,所以第二维是 k。或者说 Path[m,k] 应该是第一个被输出的。