GESP 客观题评测系统

试卷解析 · 理解每一步

普及组 CSP-J 2026 初赛模拟卷 6

CSPJ-2026-R1-Mock-6

试卷解析总览,可直接查看每题答案与解析。

一、单项选择题

(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)

第 1 题(单选题,2 分)

在计算机系统中,操作系统的主要作用是( )。

A.
将用高级语言编写的程序翻译成机器语言
B.
管理和控制计算机的硬件与软件资源
C.
进行科学计算
D.
防范计算机病毒

正确答案B

解析详情
答案 B操作系统功能
思路与推导
  1. 操作系统位于应用程序与硬件之间,统一管理处理器、内存、外设、文件等软硬件资源,并为程序运行提供服务。编译、科学计算和查杀病毒都只是特定软件的功能。

第 2 题(单选题,2 分)

在 Linux 中编译 `main.cpp` 并把可执行文件命名为 `main`,下列命令正确且不会覆盖源文件的是( )。

A.
`g++ main.cpp -o main`
B.
`g++ main -o main.cpp`
C.
`g++ -o main.cpp main.cpp`
D.
`./main.cpp -o main`

正确答案A

解析详情
答案 Ag++ 编译命令
思路与推导
  1. `g++ main.cpp -o main` 指定源文件为 `main.cpp`、输出文件为 `main`。

第 3 题(单选题,2 分)

对序列 {5,2,4,6,1,3}\{5,2,4,6,1,3\} 进行直接插入排序,在完成前 3 个元素(5,2,4)的排序后,序列的状态是( )。

A.
{2,4,5,6,1,3}\{2,4,5,6,1,3\}
B.
{2,5,4,6,1,3}\{2,5,4,6,1,3\}
C.
{4,2,5,6,1,3}\{4,2,5,6,1,3\}
D.
{5,2,4,6,1,3}\{5,2,4,6,1,3\}

正确答案A

解析详情
答案 A直接插入排序
思路与推导
  1. 先把 2 插入已排序的 `[5]`,得到 `[2,5]`;再把 4 插入 2 与 5 之间,前三个元素变为 `[2,4,5]`。未处理的后缀保持不变,故序列为 {2,4,5,6,1,3}\{2,4,5,6,1,3\}。

第 4 题(单选题,2 分)

对于变量 `x = 25, y = 7`,表达式 `(x ^ y) & ~(x & y)` 的结果是( )。

A.
25
B.
30
C.
0
D.
7

正确答案B

解析详情
答案 B位运算
思路与推导
  1. `25 = 11001₂`,`7 = 00111₂`,所以 `x ^ y = 11110₂ = 30`。又有 `x & y = 00001₂`,其按位取反的低五位为 `11110₂`,与前者再按位与仍得 30。

第 5 题(单选题,2 分)

下列几种排序算法中,在最坏情况下,( )的时间复杂度与其他三种不同。

A.
冒泡排序
B.
选择排序
C.
插入排序
D.
归并排序

正确答案D

解析详情
答案 D排序算法复杂度
思路与推导
  1. 冒泡、选择和插入排序在最坏情况下都要进行平方级比较或移动,复杂度为 O(n2)O(n^2);归并排序每层处理 nn 个元素、共 log⁡n\log n 层,最坏复杂度为 O(nlog⁡n)O(n\log n)。

第 6 题(单选题,2 分)

十六进制数 `0xDEAD` 与二进制数 `1101 1110 1010 1101` 的关系是( )。

A.
前者比后者大 1
B.
后者比前者大 1
C.
两者相等
D.
前者是后者的两倍

正确答案C

解析详情
答案 C进制转换
思路与推导
  1. 每个十六进制位对应 4 个二进制位:`D=1101`、`E=1110`、`A=1010`、`D=1101`。拼接后正好是 `1101 1110 1010 1101`,两数相等。

第 7 题(单选题,2 分)

对几乎已经排好序的数据(只有少数元素位置不对)进行排序,( )算法最快。

A.
快速排序
B.
插入排序
C.
归并排序
D.
选择排序

正确答案B

解析详情
答案 B插入排序适用性
思路与推导
  1. 插入排序的工作量与逆序对数量密切相关;数据几乎有序时,元素向前移动的距离很短,运行时间可接近 O(n)O(n)。选择排序仍固定做约 n2/2n^2/2 次比较。

第 8 题(单选题,2 分)

一个项目团队中,每个成员都与其他恰好 3 个成员有直接协作关系。如果团队有 12 人,那么协作关系总共有( )种。

A.
18
B.
36
C.
12
D.
4

正确答案A

解析详情
答案 A握手定理
思路与推导
  1. 把成员看作顶点、协作关系看作无向边,所有顶点度数之和为 12×3=3612\times3=36。每条边被两个端点各计一次,因此边数为 36/2=1836/2=18。

第 9 题(单选题,2 分)

一个栈从空开始依次执行 `push(1)`、`push(2)`、`pop()`、`push(3)`。此时栈顶元素是( )。

A.
1
B.
2
C.
栈为空
D.
3

正确答案D

解析详情
答案 D栈操作
思路与推导
  1. 压入 1、2 后弹出栈顶 2,再压入 3,因此当前栈顶是 3。

第 10 题(单选题,2 分)

从 1,2,3,…,101,2,3,\ldots,10 中选出 4 个不同的数,使得其中任意两个数的差都不小于 2,不同的选法有( )种。

A.
35
B.
70
C.
84
D.
120

正确答案A

解析详情
答案 A不相邻组合计数
思路与推导
  1. 设所选数为 x1<x2<x3<x4x_1<x_2<x_3<x_4,令 yi=xi−(i−1)y_i=x_i-(i-1),间隔条件转化为从 11 到 77 中任选 4 个不同数。故选法数为 (74)=35\binom{7}{4}=35。

第 11 题(单选题,2 分)

以下代码段的时间复杂度是( )。

for (int i = n; i > 0; i /= 2, cout << endl) {
    for (int j = 0; j < i; j++) {
        cout << i * j << " ";
    }
}
A.
O(n)O(n)
B.
O(nlog⁡n)O(n\log n)
C.
O(n2)O(n^2)
D.
O(log⁡n)O(\log n)

正确答案A

解析详情
答案 A循环复杂度求和
思路与推导
  1. 外层各轮的 `i` 依次约为 n,n/2,n/4,…n,n/2,n/4,\ldots,内层执行次数总和为 n+n/2+n/4+⋯<2nn+n/2+n/4+\cdots<2n。因此总时间复杂度为 O(n)O(n),不是外层轮数与 nn 的简单乘积。

第 12 题(单选题,2 分)

对长度为 nn 的有序数组进行二分查找,( )不是必须满足的条件。

A.
数组元素必须连续存储
B.
数组必须按关键字有序
C.
必须能够随机访问元素
D.
数据量 nn 最好较大

正确答案D

解析详情
答案 D二分查找条件
思路与推导
  1. 二分查找依靠有序性排除一半区间,并通过随机访问快速取得中点;这些条件与 nn 的大小无关。即使数组很小,算法仍能正确执行,只是效率优势不明显。

第 13 题(单选题,2 分)

一棵二叉树的前序遍历序列是 ABDECF,中序遍历序列是 DBEAFC,则其后序遍历序列是( )。

A.
DEBFCA
B.
DEBFAC
C.
DBEFCA
D.
DBECFA

正确答案A

解析详情
答案 A二叉树遍历还原
思路与推导
  1. 前序首项 A 是根,中序将其分成左子树 `DBE` 和右子树 `FC`。左子树根为 B、孩子为 D 和 E,后序为 `DEB`;右子树根为 C、左孩子为 F,后序为 `FC`,合并得 `DEBFCA`。

第 14 题(单选题,2 分)

循环队列容量为 10,`front = 7, rear = 3`,元素个数为( )。

A.
4
B.
5
C.
6
D.
7

正确答案C

解析详情
答案 C循环队列
思路与推导
  1. 循环队列元素个数按公式 `(rear - front + capacity) % capacity` 计算,即 (3−7+10) mod 10=6(3-7+10)\bmod10=6。这表示从下标 7 环绕到下标 3 共存有 6 个元素。

第 15 题(单选题,2 分)

使用邻接表存储一个有 nn 个顶点、mm 条边的无向图,保存所有邻接关系所需的空间复杂度是( )。

A.
O(1)O(1)
B.
O(n2)O(n^2)
C.
O(n+m)O(n+m)
D.
O(2n)O(2^n)

正确答案C

解析详情
答案 C图的邻接表
思路与推导
  1. 邻接表需要保存 n 个表头以及每条无向边的两个邻接记录,总空间为 O(n+m)O(n+m)。

二、阅读程序(1)

1 | #include <iostream>
2 | #include <vector>
3 | using namespace std;
4 |
5 | int solve(int n) {
6 |     int sum = 0;
7 |     for (int i = 1; i <= n / 2; i++)
8 |         if (n % i == 0) sum += i;
9 |     return sum;
10 | }
11 |
12 | int main() {
13 |     int n;
14 |     cin >> n;
15 |     int sum = solve(n);
16 |     if (sum == n) {
17 |         cout << "perfect_number" << endl;
18 |     } else if (sum > n) {
19 |         cout << "abundant_number" << endl;
20 |     } else {
21 |         cout << "deficient_number" << endl;
22 |     }
23 |     return 0;
24 | }

第 16 题(判断题,2 分)

函数 `solve` 计算的是 nn 的所有因数之和。( )

正确答案错误

解析详情
答案 错误因数枚举与完全数
思路与推导
  1. 循环只枚举 `1` 到 `n/2`,累加的是小于 `n` 的正因数,即真因数;因数 `n` 本身没有被计入。因此 `solve(n)` 不是所有正因数之和。

第 17 题(判断题,2 分)

如果 nn 是素数,那么 `solve` 的返回值总是 1。( )

正确答案正确

解析详情
答案 正确素数的真因数
思路与推导
  1. 对任意素数 `n >= 2`,在区间 `1..n/2` 中只有 1 能整除 `n`,所以循环最终得到 `sum = 1`。

第 18 题(判断题,2 分)

当 n=496n=496 时,程序会输出 `perfect_number`。( )

正确答案正确

解析详情
答案 正确完全数判定
思路与推导
  1. 496 的真因数为 1,2,4,8,16,31,62,124,2481,2,4,8,16,31,62,124,248,它们的和正好是 496。因此 `sum == n` 成立,程序输出 `perfect_number`。

第 19 题(单选题,3 分)

nn 的取值区间为 [10,100][10,100] 时,第一个输出 `abundant_number` 的 nn 是( )。

A.
10
B.
12
C.
28
D.
72

正确答案B

解析详情
答案 B盈数判定
思路与推导
  1. `solve(12)=1+2+3+4+6=16>12`,因此区间 [10,100][10,100] 中第一个输出 `abundant_number` 的数是 12,答案为 B。

第 20 题(单选题,3 分)

nn 的取值区间为 [1,1000][1,1000] 时,关于完全数(perfect number),以下说法中正确的是( )。

A.
所有完全数都是奇数
B.
所有完全数都是偶数
C.
完全数可以是素数
D.
完全数的个数是无限的

正确答案B

解析详情
答案 B完全数性质
思路与推导
  1. 在 [1,1000][1,1000] 内的完全数是 6、28、496,三者均为偶数,且都不是素数。因此在题目限定范围内,“所有完全数都是偶数”正确。

二、阅读程序(2)

1 | #include <bits/stdc++.h>
2 | using namespace std;
3 | const int N = 10009;
4 | int n, nums[N];
5 |
6 | int solve() {
7 |     int res = n;
8 |     for (int i = 0; i < n; i++) {
9 |         res ^= i;
10 |         res ^= nums[i];
11 |     }
12 |     return res;
13 | }
14 |
15 | int main() {
16 |     cin >> n;
17 |     // 保证输入的 n 个数在 0..n 范围内,且互不相同
18 |     for (int i = 0; i < n; i++) cin >> nums[i];
19 |     cout << solve() << endl;
20 |     return 0;
21 | }

第 21 题(判断题,2 分)

若输入 `5 1 2 3 4 5`,则输出结果是 0。( )

正确答案正确

解析详情
答案 正确异或消去法
思路与推导
  1. `res` 最终等于 `5 ^ (0^1^2^3^4) ^ (1^2^3^4^5)`;1 到 5 都成对异或为 0,只剩缺失的数 0。因此程序输出 0。

第 22 题(判断题,2 分)

本题输入 `nums` 数组的数据可以是无序的。( )

正确答案正确

解析详情
答案 正确异或的交换律与结合律
思路与推导
  1. 循环只对所有下标和数组元素做异或,异或满足交换律、结合律,元素出现的先后顺序不会改变最终 `res`。因此 `nums` 无须有序。

第 23 题(判断题,2 分)

程序功能是判断 nn 个数是不是连续的,如果不是连续的,则输出其中缺失的数。( )

正确答案错误

解析详情
答案 错误缺失数算法
思路与推导
  1. 在“`nums` 是 `0..n` 中互不相同的 n 个数”这一前提下,程序通过异或消去成对数字,返回唯一缺失值。它既不检查一般序列是否连续,也不能处理任意重复或越界数据。

第 24 题(单选题,4 分)

若输入 `7 7 1 6 2 5 3 0`,则输出结果是( )。

A.
0
B.
3
C.
4
D.
8

正确答案C

解析详情
答案 C异或求缺失数
思路与推导
  1. 当 `n = 7` 时完整集合是 `0..7`,输入包含 `0,1,2,3,5,6,7`,只有 4 缺失。其余数字在两组异或中各出现两次而抵消,最终 `res = 4`。

第 25 题(单选题,4 分)

算法利用的最主要的性质是( )。

A.
异或的交换律和结合律
B.
异或的交换律和分配律
C.
异或的结合律和分配律
D.
异或的交换律和幂零性

正确答案D

解析详情
答案 D异或运算性质
思路与推导
  1. 交换律允许把相同数字重排到一起,幂零性 `a ^ a = 0` 使完整集合与输入集合中的公共数字全部抵消,最后只剩缺失值。分配律不是该算法的关键。

二、阅读程序(3)

1 | #include <bits/stdc++.h>
2 | using namespace std;
3 | const int N = 100009;
4 | const int INF = 1e8 - 1;
5 | int a[N];
6 |
7 | int main() {
8 |     int n, x;
9 |     cin >> n >> x;
10 |     for (int i = 0; i < n; i++) cin >> a[i];
11 |     sort(a, a + n, less<int>());
12 |
13 |     int left = 0, right = n - 1, p = n;
14 |     while (left <= right) {
15 |         int mid = (left + right) / 2;
16 |         if (a[mid] > x) {
17 |             p = mid;
18 |             right = mid - 1;
19 |         } else {
20 |             left = mid + 1;
21 |         }
22 |     }
23 |     cout << p << " ";
24 |     if (p < n) cout << a[p] << endl;
25 |     else cout << INF << endl;
26 |     return 0;
27 | }

第 26 题(判断题,2 分)

该程序使用二分查找,找到第一个大于或等于 xx 的元素的下标和数值。( )

正确答案错误

解析详情
答案 错误二分查找边界
思路与推导
  1. 判断条件是 `a[mid] > x`,找到的是排序后第一个严格大于 `x` 的元素及其下标。若元素恰好等于 `x`,程序会执行 `left = mid + 1` 跳过它,因此不是“大于或等于”。

第 27 题(判断题,2 分)

当输入 `7 8 0 9 2 7 8 7 6` 时,程序输出为 `7 9`。( )

正确答案错误

解析详情
答案 错误二分查找过程追踪
思路与推导
  1. 排序后数组为 `[0,2,6,7,7,8,9]`。查找第一个大于 `x=8` 的位置得到 `p=6`、`a[p]=9`,程序输出 `6 9`,不是 `7 9`。

第 28 题(判断题,2 分)

数组排序后,也可以使用 `upper_bound(a, a + n, x) - a` 得到 pp 的数值。( )

正确答案正确

解析详情
答案 正确STL 二分函数
思路与推导
  1. `upper_bound(a, a + n, x)` 返回有序区间中第一个严格大于 `x` 的元素指针;减去首地址 `a` 就得到其下标。若不存在,该返回值为 `a+n`,对应程序初值 `p=n`。

第 29 题(单选题,4 分)

当输入 `8 7 3 4 4 5 5 6 6 7` 时,程序输出为( )。

A.
7 7
B.
8 7
C.
8 999999
D.
8 99999999

正确答案D

解析详情
答案 D二分查找无解边界
思路与推导
  1. 排序后最大元素仍是 7,没有元素严格大于 `x=7`,所以二分结束时 `p=n=8`。由于 `p < n` 不成立,程序输出 `INF=10^8-1=99999999`,即 `8 99999999`。

第 30 题(单选题,4 分)

对于输入的 nn 个数的序列,下列说法中正确的是( )。

A.
序列中的元素可以从大到小有序
B.
序列中的元素可以从小到大有序
C.
序列中的元素可以无序
D.
以上说法都正确

正确答案D

解析详情
答案 D排序与二分查找前置处理
思路与推导
  1. 程序读入数组后先执行 `sort(a, a+n, less<int>())`,再进行二分查找,因此原输入可以递增、递减或无序。三种输入顺序都会被统一排成升序。

三、完善程序(1)二叉树层序遍历

(二叉树层序遍历)给定一棵以结点 1 为根的二叉树。结点编号为 1ldotsn1ldots n,输入每个结点的左右孩子编号,0 表示对应孩子不存在。请按层序输出所有结点,并统计叶结点数量。保证 nge1nge1,输入构成一棵合法二叉树。

1 | #include <iostream>
2 | #include <queue>
3 | #include <vector>
4 | using namespace std;
5 | int main() {
6 |     int n;
7 |     cin >> n;
8 |     vector<int> leftChild(n + 1), rightChild(n + 1);
9 |     for (int i = 1; i <= n; ++i)
10 |         cin >> leftChild[i] >> rightChild[i];
11 |     queue<int> q;
12 |     ①;
13 |     int leaves = 0;
14 |     bool first = true;
15 |     while (!q.empty()) {
16 |         int u = q.front();
17 |         q.pop();
18 |         if (!first) cout << ' ';
19 |         cout << u;
20 |         first = false;
21 |         if (②) q.push(leftChild[u]);
22 |         if (rightChild[u] != 0) ③;
23 |         if (④) ++leaves;
24 |     }
25 |     cout << '\n' << ⑤ << '\n';
26 |     return 0;
27 | }

第 31 题(单选题,3 分)

① 处应填( )。

A.
q.push(0)
B.
q.push(n)
C.
q.push(1)
D.
q.pop()

正确答案C

解析详情
答案 C层序遍历初始化
思路与推导
  1. 根结点编号为 1,层序遍历开始前应把根结点加入队列,即执行 `q.push(1)`。

第 32 题(单选题,3 分)

② 处应填( )。

A.
leftChild[u] == 0
B.
leftChild[u] != 0
C.
u != 0
D.
rightChild[u] != 0

正确答案B

解析详情
答案 B左孩子入队
思路与推导
  1. 只有左孩子存在,即 `leftChild[u] != 0` 时,才能把它加入队列。

第 33 题(单选题,3 分)

③ 处应填( )。

A.
q.push(u)
B.
q.push(leftChild[u])
C.
q.push(rightChild[u])
D.
q.pop()

正确答案C

解析详情
答案 C右孩子入队
思路与推导
  1. 条件已经确认右孩子存在,因此应执行 `q.push(rightChild[u])`。

第 34 题(单选题,3 分)

④ 处应填( )。

A.
leftChild[u] != 0
B.
rightChild[u] != 0
C.
leftChild[u] == rightChild[u]
D.
leftChild[u] == 0 && rightChild[u] == 0

正确答案D

解析详情
答案 D叶结点判定
思路与推导
  1. 二叉树中的叶结点没有左孩子也没有右孩子,因此两个孩子编号都应为 0。

第 35 题(单选题,3 分)

⑤ 处应填( )。

A.
n
B.
leaves
C.
q.size()
D.
u

正确答案B

解析详情
答案 B统计结果
思路与推导
  1. 变量 `leaves` 在遍历过程中累计叶结点数量,遍历结束后应输出它。

三、完善程序(2)网格路径计数

(网格路径计数)给定一个 n×mn\times m 的网格,其中 `#` 表示障碍,`.` 表示可通行。只能从 (1,1)(1,1) 向下或向右移动,求到达 (n,m)(n,m) 的路径数。保证起点和终点可通行,答案不超过 `long long` 范围。

1 | #include <iostream>
2 | #include <string>
3 | using namespace std;
4 | long long dp[1005][1005];
5 | int main() {
6 |     int n, m;
7 |     cin >> n >> m;
8 |     string g[1005];
9 |     for (int i = 1; i <= n; ++i) cin >> g[i];
10 |     dp[1][1] = ①;
11 |     for (int i = 1; ②; ++i) {
12 |         for (int j = 1; j <= m; ++j) {
13 |             if (i == 1 && j == 1) continue;
14 |             if (③) dp[i][j] = 0;
15 |             else dp[i][j] = ④;
16 |         }
17 |     }
18 |     cout << ⑤ << '\n';
19 |     return 0;
20 | }

第 36 题(单选题,3 分)

① 处应填( )。

A.
-1
B.
n
C.
m
D.
1

正确答案D

解析详情
答案 D动态规划初值
思路与推导
  1. 起点到自身有一条空路径,因此应初始化 `dp[1][1]=1`。

第 37 题(单选题,3 分)

② 处应填( )。

A.
i < n
B.
i <= n
C.
i <= m
D.
i < m

正确答案B

解析详情
答案 B网格行枚举
思路与推导
  1. 网格共有 n 行且下标从 1 开始,所以外层循环条件是 `i<=n`。

第 38 题(单选题,3 分)

③ 处应填( )。

A.
g[i][j] == '.'
B.
g[i - 1][j] == '#'
C.
g[i][j - 1] == '#'
D.
g[i - 1][j - 1] == '#'

正确答案C

解析详情
答案 C字符串下标与障碍判断
思路与推导
  1. 第 i 行字符串使用从 0 开始的列下标,所以格子 (i,j)(i,j) 对应 `g[i][j-1]`;等于 `#` 时为障碍。

第 39 题(单选题,3 分)

④ 处应填( )。

A.
dp[i][j] + 1
B.
dp[i - 1][j] + dp[i][j - 1]
C.
dp[i - 1][j - 1]
D.
max(dp[i - 1][j], dp[i][j - 1])

正确答案B

解析详情
答案 B网格路径 DP
思路与推导
  1. 到达当前格的最后一步只能来自上方或左方,因此路径数为两者路径数之和。

第 40 题(单选题,3 分)

⑤ 处应填( )。

A.
dp[n][m]
B.
dp[1][1]
C.
dp[m][n]
D.
n + m

正确答案A

解析详情
答案 A状态答案
思路与推导
  1. `dp[i][j]` 表示到达 (i,j)(i,j) 的路径数,目标格答案就是 `dp[n][m]`。