一、单项选择题
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
CSPJ-2026-R1-Mock-4
试卷解析总览,可直接查看每题答案与解析。
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
在 NOI Linux 的终端中,要列出当前目录下所有文件和文件夹的详细信息(包括权限、大小、修改时间等),应该使用命令( )。
正确答案B
【答案】B
【考点】Linux 文件命令
【解析】 `ls -l` 使用长格式列出名称、权限、链接数、所有者、大小和修改时间等详细信息。
【易错点】 `ls -a` 负责显示隐藏文件,但本身不提供长格式详情。
在计算机网络中,IP 地址 192.168.1.1 属于( )地址。
正确答案C
【答案】C
【考点】IPv4 分类地址
【解析】 分类地址按首字节判断:C 类地址范围为 192~223,因此 192.168.1.1 属于 C 类。
【易错点】 不要把 192.168.0.0/16 的私有地址属性与 A、B、C 类分类混淆。
在 C++ 中,表达式 `!(5 > 3) && (4 <= 4) || (2 != 2)` 的结果是( )。
正确答案B
【答案】B
【考点】逻辑运算
【解析】 `5 > 3` 为真,取反后为假;假与任何值进行 `&&` 仍为假,`2 != 2` 也为假,所以整个表达式为 `false`。
【易错点】 逻辑运算结果虽可转换为整数 0/1,但表达式的布尔结果是 `false`。
关于单向链表,以下描述中正确的是( )。
正确答案D
【答案】D
【考点】单向链表
【解析】 单向链表的每个节点保存数据以及指向下一个节点的指针,节点不要求连续存储。
【易错点】 只有已知插入或删除位置时操作才可为 ,查找位置仍可能需要 。
对于有 个节点的二叉树,其最小高度是( )。
正确答案B
【答案】B
【考点】二叉树高度
【解析】 高度按边数计算时,高度为 的二叉树最多有 个节点;反解得最小高度为 。
【易错点】 要先确认高度从 0 开始计算,不能直接套层数公式。
将十进制小数 100.25 转换为二进制数,结果是( )。
正确答案C
【答案】C
【考点】进制转换
【解析】 整数部分 ,二进制为 `1100100`;小数 ,二进制为 `.01`,合并得 `1100100.01`。
【易错点】 小数部分应按二进制负次幂换算。
(考试成绩排序)场景:老师需要对全班 50 名学生的成绩排序,要求相同分数的学生保持原来的相对顺序。下列排序算法中最合适的是( )。
正确答案C
【答案】C
【考点】稳定排序
【解析】 归并排序在相等元素时优先取左半部分即可保持原相对顺序,是四个选项中的稳定排序。
【易错点】 快速排序、堆排序和选择排序的常见实现都不稳定。
突然断电后,数据不会丢失的存储设备是( )。
正确答案C
【答案】C
【考点】存储器易失性
【解析】 固态硬盘使用非易失性闪存,断电后仍能保存数据;内存、缓存和寄存器均为易失性存储。
【易错点】 速度快不代表断电后能够保留数据。
使用深度优先搜索(DFS)遍历一个 行 列的矩阵。从左上角开始搜索,每次只能向右或向下移动一个位置。在搜索过程中,需要使用一个栈来维护当前搜索路径上的已访问位置。为了确保能够完成整个矩阵的遍历,栈的大小至少为( )。(注:本题不考虑栈空间的大小限制。)
正确答案C
【答案】C
【考点】深度优先搜索栈
【解析】 只向右或向下移动时,从左上角到右下角的最长路径包含 个位置,因此路径栈至少要能容纳这么多元素。
【易错点】 计算节点数时不能只算移动次数 。
以下代码的时间复杂度是( )。
int n, i = 1;
cin >> n;
while (i < n) {
i = i * 3;
}正确答案C
【答案】C
【考点】循环复杂度
【解析】 变量 `i` 每轮乘 3,执行约 次;换底只带来常数因子,所以复杂度为 。
【易错点】 循环变量指数增长时,循环次数不是 。
某城市有 8 个交通枢纽,如果要建设一个完全图式的道路网络,使得任意两个枢纽之间都有直达道路,需要建设( )条道路。
正确答案A
【答案】A
【考点】完全图
【解析】 8 个顶点的无向完全图边数为 inom{8}{2}=8 imes7/2=28。
【易错点】 每条无向边连接一对顶点,不能把两个方向重复计数。
从 5 个不同的红球和 3 个不同的蓝球中,至少取 1 个球,最多取 4 个球,且红球和蓝球都必须至少取一个,不同的取法有( )种。
正确答案B
【答案】B
【考点】组合计数
【解析】 取 2、3、4 个球且两色非空的方案数分别为 15、45、65,总数为 。
【易错点】 既要排除只取一种颜色,也要注意所有球互不相同。
二叉树的节点按照先从上往下,后从左往右的顺序(对比“先行后列”的表达方式)进行编号,( )遍历方式可以按升序输出二叉搜索树的所有节点。
正确答案B(另接受:D)
【答案】B
【考点】二叉搜索树遍历
【解析】 二叉搜索树满足左子树键值小于根、右子树键值大于根,因此中序遍历会按升序输出所有节点。
【易错点】 原答案表把前半句的层次编号误当成问题答案;系统同时兼容该原表选项。
一个时间复杂度为 的算法,当 从 100 增大到 200 时,运行时间大约变为原来的( )倍。
正确答案C
【答案】C
【考点】渐进复杂度
【解析】 当输入规模变为 2 倍时,立方复杂度的运行量变为 倍。
【易错点】 不能只按输入规模的倍数线性估计运行时间。
一段时长 10 分钟的视频,分辨率为 1080P(),帧率为 30 帧/秒,颜色深度为 24 位。如果压缩比为 50:1,则压缩后的文件大小约为( )。
正确答案B
【答案】B
【考点】视频容量
【解析】 原始容量约为 GB,按 50:1 压缩后约为 2.09GB,最接近 2.1GB。
【易错点】 24 位颜色深度要先换成每像素 3 字节,并计入 10 分钟的总帧数。
1 | #include <iostream>
2 | using namespace std;
3 | int solve(int x, int y) {
4 | if (y == 0) return x;
5 | if (x < y) swap(x, y);
6 | return solve(y, x - y);
7 | }
8 | int main() {
9 | int a, b;
10 | cin >> a >> b;
11 | int k = solve(a, b);
12 | cout << a / k << "/" << b / k << endl;
13 | return 0;
14 | }
15 | // 输入的 a 和 b 是不大于 10000 的正整数函数 `solve(int x, int y)` 计算 和 的最大公约数。( )
正确答案正确
【答案】正确
【考点】最大公约数
【解析】 函数通过反复交换并相减,把问题化为更小的一对正整数;当第二个参数为 0 时,第一个参数就是最大公约数。
【易错点】 这是辗转相减法,不是求最小公倍数。
把第 5 行代码去掉,程序会正常输出,但结果数值可能不对。( )
正确答案错误
【答案】错误
【考点】递归终止
【解析】 删除交换后,若 `x < y`,下一次会传入负数 `x-y`,递归不能按预期收敛,最终可能栈溢出而无法正常输出。
【易错点】 结果错误和程序无法正常结束是不同结论。
如果输入的值为 160 和 115,则程序的输出结果为 `23/32`。( )
正确答案错误
【答案】错误
【考点】分数约分
【解析】 ,程序输出 `160/5` 与 `115/5`,即 `32/23`,不是 `23/32`。
【易错点】 分子分母的输出顺序与输入顺序一致。
如果输入 1817 和 299,则输出为( )。
正确答案D
【答案】D
【考点】最大公约数应用
【解析】 ,约分得到 、,所以输出 `79/13`。
【易错点】 必须同时用最大公约数约分分子和分母。
如果输入 为 中随机生成的数,则程序的平均时间复杂度为( )。
正确答案B
【答案】B
【考点】平均时间复杂度
【解析】 对固定较大参数,辗转相减的平均步数与调和级数同阶;再对随机输入平均后仍为 。
【易错点】 最坏情况下可达线性,题目问的是随机输入的平均复杂度。
1 | #include <iostream>
2 | using namespace std;
3 | int main() {
4 | int n, sum = 0;
5 | cin >> n;
6 | int arr[100];
7 | for (int i = 0; i < n; i++) {
8 | cin >> arr[i];
9 | }
10 | for (int i = 0; i < n; i++) {
11 | int cnt = 0;
12 | for (int j = 0; j < n; j++) {
13 | if (arr[j] > arr[i]) {
14 | cnt++;
15 | }
16 | }
17 | sum += (cnt == 1) * arr[i];
18 | }
19 | cout << sum << endl;
20 | return 0;
21 | }
22 | // 输入的所有数为绝对值均不大于 1000 的整数若输入数组为 `[5, 3, 8, 2]`,则程序输出为 5。( )
正确答案正确
【答案】正确
【考点】程序执行模拟
【解析】 数组中只有 5 恰好有一个比它大的元素 8,因此累加值为 5。
【易错点】 条件统计的是比当前元素大的元素个数,不是当前元素的下标。
数组中可能存在多个元素满足条件,程序会将它们全部累加。( )
正确答案正确
【答案】正确
【考点】重复元素与累加
【解析】 循环逐个检查数组位置;若多个元素各自满足 `cnt == 1`,语句会把它们分别加入 `sum`。
【易错点】 程序没有去重,相同数值位于不同位置时仍会分别处理。
如果程序输出为 0,则数组中的所有元素一定都相等。( )
正确答案错误
【答案】错误
【考点】反例构造
【解析】 输出 0 还可能因为严格次大值本身为 0,或最大值重复导致没有元素满足 `cnt == 1`,并不能推出所有元素相等。
【易错点】 判断充分必要条件时,应检查能产生相同输出的其他输入。
若输入数组为 `[9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2]`,则输出为( )。
正确答案C
【答案】C
【考点】程序执行模拟
【解析】 给定数组严格递减且元素互异,8 恰好只有一个更大的元素 9,因此程序输出 8。
【易错点】 最大元素的 `cnt` 为 0,不会被累加。
该程序计算的是数组中( )。
正确答案C
【答案】C
【考点】嵌套循环含义
【解析】 对每个 `arr[i]`,内层循环统计严格大于它的元素数;程序累加所有统计值恰好为 1 的元素,所以选 C。
【易错点】 它不一定等价于一个单独的“第二大值”,重复元素会影响统计。
1 | #include <iostream>
2 | #include <vector>
3 | #include <algorithm>
4 | using namespace std;
5 |
6 | int n, k, ans = 0;
7 | vector<int> nums;
8 | vector<bool> used;
9 |
10 | void dfs(int pos, int sum, int count) {
11 | if (count == k) {
12 | if (sum % 2 == 0) {
13 | ans++;
14 | }
15 | return;
16 | }
17 | if (pos >= n) return;
18 |
19 | if (!used[pos]) {
20 | used[pos] = true;
21 | dfs(pos + 1, sum + nums[pos], count + 1);
22 | used[pos] = false;
23 | }
24 |
25 | dfs(pos + 1, sum, count);
26 | }
27 |
28 | int main() {
29 | cin >> n >> k;
30 | nums.resize(n);
31 | used.resize(n, false);
32 |
33 | for (int i = 0; i < n; i++) {
34 | cin >> nums[i];
35 | }
36 |
37 | dfs(0, 0, 0);
38 | cout << ans << endl;
39 | return 0;
40 | }如果输入数据中存在重复数字,则重复数字的数量不会影响输出结果。( )
正确答案错误
【答案】错误
【考点】组合计数
【解析】 程序按数组位置选择元素,数值相同的位置仍代表不同选择,因此重复数字的数量会改变方案数。
【易错点】 不要把按位置选取误当成按不同数值选取。
去掉 `nums.resize(n);` 和 `used.resize(n, false);` 这两行代码,不会影响程序的正常运行。( )
正确答案错误
【答案】错误
【考点】vector 容量
【解析】 代码通过下标写入 `nums[i]` 和访问 `used[pos]`;删除两次 `resize` 后两个 vector 为空,会发生越界访问。
【易错点】 `reserve` 或声明 vector 并不会自动创建可用的下标元素。
如果 , 个数为 1~10 的任意排列,则输出结果是 。( )
正确答案正确
【答案】正确
【考点】奇偶组合
【解析】 1~10 含 5 个奇数和 5 个偶数;两数之和为偶数需同奇偶,方案数为 inom{5}{2}+inom{5}{2}=2inom{5}{2}。
【易错点】 奇偶各选一个得到的是奇数和。
如果输入的 为 0,则程序的输出结果为( )。
正确答案B
【答案】B
【考点】递归边界
【解析】 当 时首次调用已满足 `count == k`,且初始和 0 为偶数,因此 `ans` 加 1 后返回,输出 1。
【易错点】 选择 0 个元素的空集是一种合法选择。
程序的时间复杂度是( )。
正确答案C
【答案】C
【考点】回溯复杂度
【解析】 每个元素都有选或不选两个分支;在最坏情况下会遍历指数数量的状态,所以时间复杂度为 。
【易错点】 固定很小的 可减少状态,但题目没有给出这样的限制。
归并排序算法通过递归地将数组不断地分割为更小的子数组,然后将这些子数组合并成有序数组,最终完成整个数组的排序。该排序为稳定排序,且时间复杂度较低。
1 | #include <iostream>
2 | #define N 100009
3 | using namespace std;
4 | int n;
5 | int a[N], L[N], R[N];
6 |
7 | void merge(int l, int m, int r) {
8 | int n1 = m - l + 1;
9 | int n2 = r - m;
10 |
11 | for (int i = 0; i < n1; i++)
12 | L[i] = a[l + i];
13 | for (int j = 0; j < n2; j++)
14 | R[j] = a[①];
15 |
16 | int i = 0, j = 0, k = l;
17 | while (②) {
18 | if (L[i] <= R[j]) {
19 | a[k] = L[i++];
20 | } else {
21 | a[k] = R[j++];
22 | }
23 | ++k;
24 | }
25 | while (i < n1) {
26 | a[k++] = L[i++];
27 | }
28 | while (j < n2) {
29 | a[k++] = R[j++];
30 | }
31 | }
32 |
33 | void mSort(int left, int right) {
34 | if (left < right) {
35 | int mid = left + (right - left) / 2;
36 | mSort(left, mid);
37 | mSort(mid + 1, right);
38 | merge(③);
39 | }
40 | }
41 |
42 | int main() {
43 | cin >> n;
44 | for (int i = 0; i < n; i++) {
45 | cin >> a[i];
46 | }
47 | mSort(④);
48 | for (int i = 0; i < n - 1; i++) {
49 | cout << a[i] << " ";
50 | }
51 | cout << ⑤ << endl;
52 | return 0;
53 | }
54 |
55 |
56 |① 处应填( )。
jj + 1m + jm + 1 + j正确答案D
【答案】D
【考点】归并排序右半段
【解析】 右子数组从原数组下标 开始,第 个元素应取 `a[m + 1 + j]`。
【易错点】 `j` 是临时数组下标,不能直接作为原数组下标。
② 处应填( )。
i < n && j < ni <= n && j <= ni < n1 && j < n2i <= n1 && j <= n2正确答案C
【答案】C
【考点】归并边界
【解析】 合并时只有 `i < n1 && j < n2` 才能同时安全读取 `L[i]` 和 `R[j]`。
【易错点】 数组下标到长度减 1 为止,不能使用 `<=`。
③ 处应填( )。
mid, left, rightright, left, midleft, mid, rightleft, right, mid正确答案C
【答案】C
【考点】归并函数参数
【解析】 当前待合并区间为 `[left,right]`,分界点是 `mid`,与 `merge(l,m,r)` 对应,应传 `left, mid, right`。
【易错点】 参数顺序由函数签名决定。
④ 处应填( )。
0, n - 10, n1, n - 11, n正确答案A
【答案】A
【考点】归并排序区间
【解析】 数组有效下标是 0 到 ,首次排序应调用 `mSort(0, n - 1)`。
【易错点】 把右端点写成 n 会访问数组范围外的位置。
⑤ 处应填( )。
" " << a[n - 1]a[n - 1]" " << a[n]a[n]正确答案B
【答案】B
【考点】格式化输出
【解析】 循环已输出前 个元素及其后的空格,最后只需输出 `a[n - 1]`,即可避免行末多余空格。
【易错点】 `a[n]` 越界,而再输出前导空格会产生两个连续空格。
波动序列指序列中的元素值交替上升和下降,最长波动子序列是已有的序列中满足这种波动性质的最长子序列。
1 | #include <iostream>
2 | #include <vector>
3 | #include <algorithm>
4 | #define N 1009
5 | using namespace std;
6 | int n;
7 | int dp[N][2];
8 | int main() {
9 | cin >> n;
10 | vector<int> nums(n);
11 | for (int i = 0; i < n; i++) {
12 | cin >> nums[i];
13 | }
14 |
15 | ①
16 | for (int i = 1; i < n; i++) {
17 | for (int j = 0; ②; j++) {
18 | if (③) {
19 | int tmp = dp[j][1] + 1;
20 | if (tmp > dp[i][0]) {
21 | dp[i][0] = tmp;
22 | }
23 | }
24 | else if (nums[i] < nums[j]) {
25 | int tmp = ④;
26 | if (tmp > dp[i][1]) {
27 | dp[i][1] = tmp;
28 | }
29 | }
30 | }
31 | }
32 |
33 |
34 | int max_Len = 1;
35 | for (int i = 1; i < n; i++) {
36 | max_Len = max(max_Len, ⑤);
37 | }
38 |
39 | cout << max_Len << endl;
40 |
41 | return 0;
42 | }① 处应填( )。
memset(dp, 1, sizeof(dp));memset(dp, 0x3f, sizeof(dp));fill(dp, dp + n * 2, 1);fill(dp[0], dp[0] + n * 2, 1);正确答案D
【答案】D
【考点】二维数组初始化
【解析】 `dp` 的 个连续整数都应初始化为 1,`fill(dp[0], dp[0] + n * 2, 1)` 能完成该操作。
【易错点】 `memset(...,1,...)` 会把每个字节写成 1,整数值并不是 1。
② 处应填( )。
j < nj <= nj < ij <= i正确答案C
【答案】C
【考点】动态规划枚举
【解析】 计算第 个位置的状态时,只能从它之前的下标转移,因此应枚举 `j < i`。
【易错点】 若允许 `j == i`,会用当前尚未完成的状态自我转移。
③ 处应填( )。
nums[i] > nums[j]nums[i] >= nums[j]nums[j] > nums[i]nums[j] >= nums[i]正确答案A
【答案】A
【考点】波动子序列状态
【解析】 后续更新 `dp[i][0]` 使用的是以下降结束的 `dp[j][1]`,因此当前一步必须上升,即 `nums[i] > nums[j]`。
【易错点】 相等元素不能形成上升或下降。
④ 处应填( )。
dp[i][0] + 1dp[i][1] + 1dp[j][0] + 1dp[j][1] + 1正确答案C
【答案】C
【考点】动态规划转移
【解析】 当 `nums[i] < nums[j]` 时形成一次下降,应由以前一个位置上升结束的状态转移,故为 `dp[j][0] + 1`。
【易错点】 新状态属于 i,转移来源仍应是 j 的相反方向状态。
⑤ 处应填( )。
dp[i][0]dp[i][1]max(dp[i][0], dp[i][1])min(dp[i][0], dp[i][1])正确答案C
【答案】C
【考点】最长波动子序列
【解析】 以位置 结尾的最优长度可能最后上升,也可能最后下降,应取 `max(dp[i][0], dp[i][1])`。
【易错点】 只检查其中一个方向会漏掉另一类最优序列。