GESP 客观题评测系统

试卷解析 · 理解每一步

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

CSPJ-2026-R1-Mock-3

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

一、单项选择题

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

第 1 题(单选题,2 分)

在计算机内部,传送、存储和加工处理数据或指令都是以( )形式进行的。

A.
二进制码
B.
八进制码
C.
十进制码
D.
智能拼音码

正确答案A

解析详情
答案 A二进制编码
思路与推导
  1. 计算机内部的数字电路用两个稳定状态表示信息,因此数据和指令都以二进制码传送、存储和处理。

第 2 题(单选题,2 分)

计算机的软件系统通常分为( )。

A.
硬件系统和软件系统
B.
高级软件和一般软件
C.
系统软件和应用软件
D.
军用软件和民用软件

正确答案C

解析详情
答案 C软件系统分类
思路与推导
  1. 计算机软件系统通常分为系统软件和应用软件两大类。系统软件负责管理资源并为应用提供运行环境。

第 3 题(单选题,2 分)

执行 `int x = 5; cout << (x << 2);` 后,输出结果是( )。

A.
10
B.
12
C.
20
D.
25

正确答案C

解析详情
答案 C左移运算
思路与推导
  1. 正整数 5 左移 2 位相当于乘以 222^2,结果为 20。

第 4 题(单选题,2 分)

一棵二叉树的中序遍历序列为 DGBAECHF,后序遍历序列为 GDBEHFCA,则前序遍历序列为( )。

A.
ABCDFGHE
B.
ABDGCEFH
C.
ACBGDHEF
D.
ACEFHBGD

正确答案B

解析详情
答案 B二叉树遍历
思路与推导
  1. 后序序列末尾确定根为 A。结合中序与后序可依次还原左子树前序为 BDG、右子树前序为 CEFH,所以整树前序为 ABDGCEFH。

第 5 题(单选题,2 分)

执行下面代码后,字符串 `t` 的值为( )。

string s = "cspj";
string t = s.substr(1, 2);
A.
`cs`
B.
`sp`
C.
`spj`
D.
`pj`

正确答案B

解析详情
答案 Bstring 子串
思路与推导
  1. `substr(1,2)` 从下标 1 开始取 2 个字符,即 `s`、`p`,所以得到 `sp`。

第 6 题(单选题,2 分)

计算机网络最主要的优点是( )。

A.
运算速度快
B.
共享资源
C.
精度高
D.
存储容量大

正确答案B

解析详情
答案 B计算机网络
思路与推导
  1. 计算机网络把分散的计算机和设备连接起来,最主要的优势是共享硬件、软件和数据等资源。

第 7 题(单选题,2 分)

下列 4 个不同进制表示的数中,最大的一个数是( )。

A.
(220.1)10(220.1)_{10}
B.
(11011011.1)2(11011011.1)_{2}
C.
(334.1)8(334.1)_{8}
D.
(DC.1)16(DC.1)_{16}

正确答案C

解析详情
答案 C进制转换
思路与推导
  1. 四个数换算成十进制分别为 220.1、219.5、220.125、220.0625,因此八进制的 (334.1)8(334.1)_8 最大。

第 8 题(单选题,2 分)

使用命令 `g++ a.cpp -o a` 编译成功后,源代码文件仍然是( )。

A.
`a.cpp`
B.
`a`
C.
`a.o`
D.
`g++`

正确答案A

解析详情
答案 A编译输入与输出
思路与推导
  1. `a.cpp` 是输入的源代码文件,`-o a` 指定生成的可执行文件名为 `a`,源文件名称不变。

第 9 题(单选题,2 分)

一般来说,在 TCP/IP 协议族中 IP 提供的服务属于( )。

A.
运输层服务
B.
会话层服务
C.
表示层服务
D.
网络层服务

正确答案D

解析详情
答案 DTCP/IP 分层
思路与推导
  1. IP 协议负责寻址与分组转发,属于 TCP/IP 的网络层。

第 10 题(单选题,2 分)

执行下面代码后,`a` 的值为( )。

void add(int &x) { x += 3; }
int a = 4;
add(a);
A.
3
B.
4
C.
7
D.
12

正确答案C

解析详情
答案 C引用参数
思路与推导
  1. 形参 `x` 是 `a` 的引用,函数中的加 3 会直接修改 `a`,所以结果为 7。

第 11 题(单选题,2 分)

一个栈的输入顺序为 1, 2, 3, 4, 5,下列序列中可能是栈的输出序列的是( )。

A.
54312
B.
24135
C.
21543
D.
12534

正确答案C

解析详情
答案 C栈的出栈序列
思路与推导
  1. 序列 21543 可通过依次压入 1、2 后弹出 2、1,再压入 3、4、5 后弹出 5、4、3 得到。

第 12 题(单选题,2 分)

对无权图进行广度优先搜索时,用来保存待访问顶点的典型数据结构是( )。

A.
集合
B.
数组排序
C.
栈
D.
队列

正确答案D

解析详情
答案 D广度优先搜索
思路与推导
  1. BFS 按发现先后依次扩展顶点,需要先进先出的队列保存待访问顶点。

第 13 题(单选题,2 分)

函数定义如下,`f(5)` 的返回值是( )。

int f(int n) {
    if (n <= 0) return 0;
    return n + f(n - 2);
}
A.
5
B.
8
C.
9
D.
15

正确答案C

解析详情
答案 C递归求值
思路与推导
  1. `f(5)=5+f(3)=5+3+f(1)=5+3+1+f(-1)=9`。

第 14 题(单选题,2 分)

下列排序算法中,最适合对大量取值范围很小的非负整数进行线性时间排序的是( )。

A.
快速排序
B.
堆排序
C.
选择排序
D.
计数排序

正确答案D

解析详情
答案 D计数排序
思路与推导
  1. 当值域很小时,计数排序可统计每个值的出现次数,时间复杂度为 O(n+k)O(n+k)。

第 15 题(单选题,2 分)

一个无向图有 6 个顶点、9 条边,则所有顶点的度数之和为( )。

A.
18
B.
9
C.
15
D.
54

正确答案A

解析详情
答案 A握手定理
思路与推导
  1. 无向图中每条边对两个端点的度数各贡献 1,因此度数总和为 2m=182m=18。

二、阅读程序(1)

(程序输入不超过数组定义的范围;判断题正确填 ✓,错误填 ✗。)

下面的程序使用直接插入排序将整数序列按升序排列,并统计元素向后移动的总次数。

 1 | #include <iostream>
 2 | using namespace std;
 3 | int a[10005];
 4 | int main() {
 5 |     int n;
 6 |     cin >> n;
 7 |     for (int i = 0; i < n; ++i) cin >> a[i];
 8 |     long long moves = 0;
 9 |     for (int i = 1; i < n; ++i) {
10 |         int key = a[i], j = i - 1;
11 |         while (j >= 0 && a[j] > key) {
12 |             a[j + 1] = a[j];
13 |             --j;
14 |             ++moves;
15 |         }
16 |         a[j + 1] = key;
17 |     }
18 |     for (int i = 0; i < n; ++i)
19 |         cout << a[i] << (i + 1 == n ? '\n' : ' ');
20 |     cout << moves << '\n';
21 |     return 0;
22 | }

第 16 题(判断题,1 分)

(1 分)外层循环第 ii 轮结束后,子数组 `a[0..i]` 一定按严格递减顺序排列。( )

正确答案错误

解析详情
答案 错误插入排序循环不变量
思路与推导
  1. 程序执行的是升序插入排序,且相等元素可以并列,因此子数组不会按严格递减顺序排列,本说法错误。

第 17 题(判断题,1 分)

(1 分)将条件 `a[j] > key` 保持不变时,这个插入排序是稳定的。( )

正确答案正确

解析详情
答案 正确排序稳定性
思路与推导
  1. 只有前面的元素严格大于 `key` 时才会移动;相等元素不会越过彼此,所以排序稳定。

第 18 题(判断题,2 分)

若输入序列本来已经按非递减顺序排列,则 `moves` 的最终值为 0。( )

正确答案正确

解析详情
答案 正确插入排序最好情况
思路与推导
  1. 已有序时每一轮都有 `a[j] <= key`,内层循环不会执行,因此没有元素后移,`moves=0`。

第 19 题(判断题,2 分)

若输入为 `5 5 4 3 2 1`,程序先输出 `1 2 3 4 5`,下一行输出 10。( )

正确答案正确

解析详情
答案 正确逆序序列与移动次数
思路与推导
  1. 完全逆序的 5 个数共有 5×4/2=105\times4/2=10 个逆序对;插入排序每消除一个逆序对移动一次,因此输出的移动次数是 10。

第 20 题(单选题,3 分)

若把第 11 行的 `a[j] > key` 改为 `a[j] < key`,其他代码不变,程序将把序列按( )排列。

A.
原顺序
B.
随机顺序
C.
非递增顺序
D.
绝对值升序

正确答案C

解析详情
答案 C插入排序方向
思路与推导
  1. 条件改为前面元素小于 `key` 时向后移动,相当于把较大的 key 插到前面,最终得到非递增序列。

第 21 题(单选题,3 分)

该程序在最坏情况下的时间复杂度是( )。

A.
O(1)O(1)
B.
O(log⁡n)O(\log n)
C.
O(n)O(n)
D.
O(n2)O(n^2)

正确答案D

解析详情
答案 D插入排序复杂度
思路与推导
  1. 逆序输入时,第 i 轮最多移动 i 个元素,总次数为 1+2+⋯+(n−1)=O(n2)1+2+\cdots+(n-1)=O(n^2)。

二、阅读程序(2)

下面的程序判断一个只包含字符 `(` 和 `)` 的字符串是否为合法括号序列。

 1 | #include <iostream>
 2 | #include <stack>
 3 | #include <string>
 4 | using namespace std;
 5 | int main() {
 6 |     string s;
 7 |     cin >> s;
 8 |     stack<char> st;
 9 |     bool ok = true;
10 |     for (char c : s) {
11 |         if (c == '(') {
12 |             st.push(c);
13 |         } else if (st.empty()) {
14 |             ok = false;
15 |             break;
16 |         } else {
17 |             st.pop();
18 |         }
19 |     }
20 |     if (!st.empty()) ok = false;
21 |     cout << (ok ? "YES" : "NO") << '\n';
22 |     return 0;
23 | }

第 22 题(判断题,2 分)

程序使用栈保存尚未匹配的左括号。( )

正确答案正确

解析详情
答案 正确栈与括号匹配
思路与推导
  1. 遇到左括号时执行 `st.push(c)`,遇到可匹配的右括号时弹出一个左括号,因此栈保存的是尚未匹配的左括号。

第 23 题(判断题,2 分)

输入为 `)` 时,程序输出 `YES`。( )

正确答案错误

解析详情
答案 错误右括号失配
思路与推导
  1. 处理第一个右括号时栈为空,程序把 `ok` 设为 false 并退出循环,所以输出 `NO`。

第 24 题(判断题,2 分)

输入为 `(()())` 时,程序输出 `YES`。( )

正确答案正确

解析详情
答案 正确合法括号序列
思路与推导
  1. 扫描过程中每个右括号都能与最近的未匹配左括号配对,结束时栈为空,因此输出 `YES`。

第 25 题(判断题,2 分)

若删去第 20 行 `if (!st.empty()) ok = false;`,某些原本应输出 `NO` 的输入会错误地输出 `YES`。( )

正确答案正确

解析详情
答案 正确括号匹配收尾检查
思路与推导
  1. 例如输入 `((` 时扫描途中不会遇到空栈右括号,但结束时仍有两个左括号未匹配;删去收尾检查就会误判为合法。

第 26 题(单选题,3 分)

若输入为 `())(`,程序输出( )。

A.
`NO`
B.
`YES`
C.
`)`
D.
程序无输出

正确答案A

解析详情
答案 A括号序列模拟
思路与推导
  1. 前两个字符完成一次匹配,第三个字符是右括号且此时栈为空,程序立即判定非法并输出 `NO`。

第 27 题(单选题,3 分)

长度为 nn 的输入使栈达到最大规模时,程序的额外空间复杂度为( )。

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

正确答案B

解析详情
答案 B栈空间复杂度
思路与推导
  1. 当输入包含 n 个左括号时,栈中最多保存 n 个字符,所以额外空间为 O(n)O(n)。

二、阅读程序(3)

 1 | #include <bits/stdc++.h>
 2 | using namespace std;
 3 | int t, x[100], a[100];
 4 | void work(int d, int i, int n) {
 5 |     int k;
 6 |     if (n == 1) {
 7 |         for (k = 0; k < d; k++)
 8 |             printf("%3d", a[k]);
 9 |         printf("\n");
10 |     } else for (k = i; k < t; k++)
11 |         if (n % x[k] == 0) {
12 |             a[d] = x[k];
13 |             work(d + 1, k, n / x[k]);
14 |         }
15 | }
16 |
17 | int main() {
18 |     int i, k, n;
19 |     cin >> n;
20 |     for (i = n; i > 1; i--)
21 |         if (n % i == 0) x[t++] = i;
22 |     work(0, 0, n);
23 |     return 0;
24 | }

第 28 题(判断题,2 分)

`main()` 函数里的 `for` 循环的作用是求出 nn 的所有因数。

正确答案错误

解析详情
答案 错误因数枚举
思路与推导
  1. 主函数循环只枚举从 nn 到 2 的因数,没有把 1 加入数组,因此并未求出 nn 的所有因数。

第 29 题(判断题,2 分)

该程序的作用是对 nn 进行素因数分解。

正确答案错误

解析详情
答案 错误乘积分解
思路与推导
  1. 递归枚举的是把 nn 写成若干个大于 1 的因数乘积的方案,因子不要求都是质数,所以不是单纯的素因数分解。

第 30 题(判断题,2 分)

去掉 `printf("%3d", a[k]);` 中的 `3` 对程序没有影响。

正确答案错误

解析详情
答案 错误格式化输出
思路与推导
  1. `%3d` 指定最小字段宽度为 3;去掉 3 会改变数字前的补空格,从而改变输出格式。

第 31 题(判断题,2 分)

去掉 `if (n % x[k] == 0)` 对程序有影响。

正确答案正确

解析详情
答案 正确递归合法性判断
思路与推导
  1. 递归参数 `n` 会不断除去已选因数,此时剩余值未必还能被后续的 `x[k]` 整除;删除判断会进入非法分解,因此会影响程序。

第 32 题(单选题,3 分)

如果输入为 2,那么输出为( )。

A.
2
B.
2 1
C.
1 2
D.
2 2

正确答案A

解析详情
答案 A程序输出模拟
思路与推导
  1. 输入 2 时数组中只有因数 2,递归选择 2 后剩余值为 1,于是输出唯一一行 `2`。

第 33 题(单选题,3 分)

如果输入为 72,那么输出的非回车字符有( )行。

A.
14
B.
15
C.
16
D.
17

正确答案C

解析详情
答案 C递归枚举计数
思路与推导
  1. 程序对 72 枚举出 16 种非增因数乘积分解方案,因此共有 16 行非空输出。

三、完善程序(1)坐标统计

输入 nn 个整点在平面上的坐标。每个点可以控制所有位于它左下方的点(即 xx、yy 坐标都比它小的点),它可以控制的点的数目称为“战斗力”。依次输出每个点的战斗力,最后输出战斗力最高的点的编号(如果若干个点的战斗力并列最高,则输出编号最大的那个)。

 1 | #include <iostream>
 2 | using namespace std;
 3 | const int SIZE = 100;
 4 | int x[SIZE], y[SIZE], f[SIZE];
 5 | int n, i, j, max_f, ans;
 6 | int main() {
 7 |     cin >> n;
 8 |     for (i = 1; i <= n; i++) cin >> x[i] >> y[i];
 9 |     max_f = 0;
10 |     for (i = 1; i <= n; i++) {
11 |         f[i] = ①;
12 |         for (j = 1; j <= n; j++) {
13 |             if (x[j] < x[i] && ②)
14 |                 ③;
15 |         }
16 |         if ④ {
17 |             max_f = f[i];
18 |             ⑤;
19 |         }
20 |     }
21 |     for (int i = 1; i <= n; i++) cout << f[i] << endl;
22 |     cout << ans << endl;
23 |     return 0;
24 | }

第 34 题(单选题,3 分)

① 处应填( )。

A.
0
B.
1
C.
i
D.
INT_MAX

正确答案A

解析详情
答案 A计数数组初始化
思路与推导
  1. 每个点的战斗力都应从 0 开始累计,所以处理第 ii 个点前应令 `f[i] = 0`。

第 35 题(单选题,3 分)

② 处应填( )。

A.
y[j] <= y[i]
B.
y[j] < y[i]
C.
y[j] > y[i]
D.
y[j] >= y[i]

正确答案B

解析详情
答案 B左下方判定
思路与推导
  1. 点 jj 位于点 ii 左下方要求两个坐标都严格更小;已有 `x[j] < x[i]`,还需 `y[j] < y[i]`。

第 36 题(单选题,3 分)

③ 处应填( )。

A.
ans = i
B.
f[i]++
C.
f[i]--
D.
ans++

正确答案B

解析详情
答案 B战斗力计数
思路与推导
  1. 每发现一个满足条件的点 jj,就应把当前点 ii 的战斗力加 1,即执行 `f[i]++`。

第 37 题(单选题,3 分)

④ 处应填( )。

A.
f[i] > max_f
B.
f[i] >= max_f
C.
f[i] < max_f
D.
f[i] <= max_f

正确答案B

解析详情
答案 B最大值与并列规则
思路与推导
  1. 需要选择最大战斗力;并列时取编号最大的。由于 ii 从小到大枚举,条件应为 `f[i] >= max_f`,相等时也更新。

第 38 题(单选题,3 分)

⑤ 处应填( )。

A.
ans++
B.
ans += max_f
C.
ans = i
D.
ans = max_f

正确答案C

解析详情
答案 C最优编号记录
思路与推导
  1. 更新最大战斗力时,应同步记录当前点编号,所以填 `ans = i`。

三、完善程序(2)排列数

输入两个正整数 n,mn,m(1<n<201<n<20,1≤m<n1\leq m<n),在 1∼n1\sim n 中任取 mm 个数,按字典序从小到大输出所有这样的排列。

样例输入:

3 2

样例输出:

1 2
1 3
2 1
2 3
3 1
3 2
 1 | #include <iostream>
 2 | #include <cstring>
 3 | using namespace std;
 4 | const int SIZE = 25;
 5 | bool used[SIZE];
 6 | int data[SIZE];
 7 | int n, m, i, j, k;
 8 | bool flag;
 9 |
10 | int main() {
11 |     cin >> n >> m;
12 |     memset(used, false, sizeof(used));
13 |     for (i = 1; i <= m; i++) {
14 |         data[i] = i;
15 |         used[i] = true;
16 |     }
17 |     flag = true;
18 |     while (flag) {
19 |         for (i = 1; i <= m - 1; i++)
20 |             cout << data[i] << " ";
21 |         cout << data[m] << endl;
22 |         flag = ①;
23 |         for (i = m; i >= 1; i--) {
24 |             ②;
25 |             for (j = data[i] + 1; j <= n; j++)
26 |                 if (!used[j]) {
27 |                     used[j] = true;
28 |                     data[i] = ③;
29 |                     flag = true;
30 |                     break;
31 |                 }
32 |             if (flag) {
33 |                 for (k = i + 1; k <= m; k++)
34 |                     for (j = 1; j <= ④; j++)
35 |                         if (!used[j]) {
36 |                             data[k] = j;
37 |                             used[j] = true;
38 |                             break;
39 |                         }
40 |                 ⑤;
41 |             }
42 |         }
43 |     }
44 |     return 0;
45 | }

第 39 题(单选题,3 分)

① 处应填( )。

A.
false
B.
true
C.
1
D.
-1

正确答案A

解析详情
答案 A循环状态初始化
思路与推导
  1. 每轮输出当前排列后,先假设不存在下一排列,令 `flag = false`;只有成功找到可增大的位置时才重新设为 true。

第 40 题(单选题,3 分)

② 处应填( )。

A.
used[i] = true
B.
data[i] = i
C.
used[data[i]] = true
D.
used[data[i]] = false

正确答案D

解析详情
答案 D排列状态维护
思路与推导
  1. 尝试增大第 ii 位前,应先释放当前值,使其可在后续位置重新使用,因此执行 `used[data[i]] = false`。

第 41 题(单选题,3 分)

③ 处应填( )。

A.
j
B.
i
C.
true
D.
false

正确答案A

解析详情
答案 A下一字典序排列
思路与推导
  1. 内层循环找到第一个可用的更大值 `j` 后,应令 `data[i] = j`。

第 42 题(单选题,3 分)

④ 处应填( )。

A.
n
B.
m
C.
i
D.
j

正确答案A

解析详情
答案 A贪心补全后缀
思路与推导
  1. 第 ii 位增大后,后续各位要按从小到大选择整个值域 11 到 nn 中尚未使用的数,所以循环上界填 `n`。

第 43 题(单选题,3 分)

⑤ 处应填( )。

A.
return 0
B.
exit
C.
continue
D.
break

正确答案D

解析详情
答案 D循环控制
思路与推导
  1. 成功构造出下一排列后应跳出从后向前寻找位置的 `for` 循环,返回 `while` 顶部输出新排列,因此填 `break`。