一、单项选择题
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
试卷解析 · 理解每一步
CSPJ-2026-R1-Mock-6
试卷解析总览,可直接查看每题答案与解析。
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
在计算机系统中,操作系统的主要作用是( )。
正确答案B
操作系统位于应用程序与硬件之间,统一管理处理器、内存、外设、文件等软硬件资源,并为程序运行提供服务。编译、科学计算和查杀病毒都只是特定软件的功能。
在 Linux 中编译 `main.cpp` 并把可执行文件命名为 `main`,下列命令正确且不会覆盖源文件的是( )。
正确答案A
`g++ main.cpp -o main` 指定源文件为 `main.cpp`、输出文件为 `main`。
对序列 进行直接插入排序,在完成前 3 个元素(5,2,4)的排序后,序列的状态是( )。
正确答案A
先把 2 插入已排序的 `[5]`,得到 `[2,5]`;再把 4 插入 2 与 5 之间,前三个元素变为 `[2,4,5]`。未处理的后缀保持不变,故序列为 。
对于变量 `x = 25, y = 7`,表达式 `(x ^ y) & ~(x & y)` 的结果是( )。
正确答案B
`25 = 11001₂`,`7 = 00111₂`,所以 `x ^ y = 11110₂ = 30`。又有 `x & y = 00001₂`,其按位取反的低五位为 `11110₂`,与前者再按位与仍得 30。
下列几种排序算法中,在最坏情况下,( )的时间复杂度与其他三种不同。
正确答案D
冒泡、选择和插入排序在最坏情况下都要进行平方级比较或移动,复杂度为 ;归并排序每层处理 个元素、共 层,最坏复杂度为 。
十六进制数 `0xDEAD` 与二进制数 `1101 1110 1010 1101` 的关系是( )。
正确答案C
每个十六进制位对应 4 个二进制位:`D=1101`、`E=1110`、`A=1010`、`D=1101`。拼接后正好是 `1101 1110 1010 1101`,两数相等。
对几乎已经排好序的数据(只有少数元素位置不对)进行排序,( )算法最快。
正确答案B
插入排序的工作量与逆序对数量密切相关;数据几乎有序时,元素向前移动的距离很短,运行时间可接近 。选择排序仍固定做约 次比较。
一个项目团队中,每个成员都与其他恰好 3 个成员有直接协作关系。如果团队有 12 人,那么协作关系总共有( )种。
正确答案A
把成员看作顶点、协作关系看作无向边,所有顶点度数之和为 。每条边被两个端点各计一次,因此边数为 。
一个栈从空开始依次执行 `push(1)`、`push(2)`、`pop()`、`push(3)`。此时栈顶元素是( )。
正确答案D
压入 1、2 后弹出栈顶 2,再压入 3,因此当前栈顶是 3。
从 中选出 4 个不同的数,使得其中任意两个数的差都不小于 2,不同的选法有( )种。
正确答案A
设所选数为 ,令 ,间隔条件转化为从 到 中任选 4 个不同数。故选法数为 。
以下代码段的时间复杂度是( )。
for (int i = n; i > 0; i /= 2, cout << endl) {
for (int j = 0; j < i; j++) {
cout << i * j << " ";
}
}正确答案A
外层各轮的 `i` 依次约为 ,内层执行次数总和为 。因此总时间复杂度为 ,不是外层轮数与 的简单乘积。
对长度为 的有序数组进行二分查找,( )不是必须满足的条件。
正确答案D
二分查找依靠有序性排除一半区间,并通过随机访问快速取得中点;这些条件与 的大小无关。即使数组很小,算法仍能正确执行,只是效率优势不明显。
一棵二叉树的前序遍历序列是 ABDECF,中序遍历序列是 DBEAFC,则其后序遍历序列是( )。
正确答案A
前序首项 A 是根,中序将其分成左子树 `DBE` 和右子树 `FC`。左子树根为 B、孩子为 D 和 E,后序为 `DEB`;右子树根为 C、左孩子为 F,后序为 `FC`,合并得 `DEBFCA`。
循环队列容量为 10,`front = 7, rear = 3`,元素个数为( )。
正确答案C
循环队列元素个数按公式 `(rear - front + capacity) % capacity` 计算,即 。这表示从下标 7 环绕到下标 3 共存有 6 个元素。
使用邻接表存储一个有 个顶点、 条边的无向图,保存所有邻接关系所需的空间复杂度是( )。
正确答案C
邻接表需要保存 n 个表头以及每条无向边的两个邻接记录,总空间为 。
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 | }函数 `solve` 计算的是 的所有因数之和。( )
正确答案错误
循环只枚举 `1` 到 `n/2`,累加的是小于 `n` 的正因数,即真因数;因数 `n` 本身没有被计入。因此 `solve(n)` 不是所有正因数之和。
如果 是素数,那么 `solve` 的返回值总是 1。( )
正确答案正确
对任意素数 `n >= 2`,在区间 `1..n/2` 中只有 1 能整除 `n`,所以循环最终得到 `sum = 1`。
当 时,程序会输出 `perfect_number`。( )
正确答案正确
496 的真因数为 ,它们的和正好是 496。因此 `sum == n` 成立,程序输出 `perfect_number`。
的取值区间为 时,第一个输出 `abundant_number` 的 是( )。
正确答案B
`solve(12)=1+2+3+4+6=16>12`,因此区间 中第一个输出 `abundant_number` 的数是 12,答案为 B。
的取值区间为 时,关于完全数(perfect number),以下说法中正确的是( )。
正确答案B
在 内的完全数是 6、28、496,三者均为偶数,且都不是素数。因此在题目限定范围内,“所有完全数都是偶数”正确。
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 | }若输入 `5 1 2 3 4 5`,则输出结果是 0。( )
正确答案正确
`res` 最终等于 `5 ^ (0^1^2^3^4) ^ (1^2^3^4^5)`;1 到 5 都成对异或为 0,只剩缺失的数 0。因此程序输出 0。
本题输入 `nums` 数组的数据可以是无序的。( )
正确答案正确
循环只对所有下标和数组元素做异或,异或满足交换律、结合律,元素出现的先后顺序不会改变最终 `res`。因此 `nums` 无须有序。
程序功能是判断 个数是不是连续的,如果不是连续的,则输出其中缺失的数。( )
正确答案错误
在“`nums` 是 `0..n` 中互不相同的 n 个数”这一前提下,程序通过异或消去成对数字,返回唯一缺失值。它既不检查一般序列是否连续,也不能处理任意重复或越界数据。
若输入 `7 7 1 6 2 5 3 0`,则输出结果是( )。
正确答案C
当 `n = 7` 时完整集合是 `0..7`,输入包含 `0,1,2,3,5,6,7`,只有 4 缺失。其余数字在两组异或中各出现两次而抵消,最终 `res = 4`。
算法利用的最主要的性质是( )。
正确答案D
交换律允许把相同数字重排到一起,幂零性 `a ^ a = 0` 使完整集合与输入集合中的公共数字全部抵消,最后只剩缺失值。分配律不是该算法的关键。
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 | }该程序使用二分查找,找到第一个大于或等于 的元素的下标和数值。( )
正确答案错误
判断条件是 `a[mid] > x`,找到的是排序后第一个严格大于 `x` 的元素及其下标。若元素恰好等于 `x`,程序会执行 `left = mid + 1` 跳过它,因此不是“大于或等于”。
当输入 `7 8 0 9 2 7 8 7 6` 时,程序输出为 `7 9`。( )
正确答案错误
排序后数组为 `[0,2,6,7,7,8,9]`。查找第一个大于 `x=8` 的位置得到 `p=6`、`a[p]=9`,程序输出 `6 9`,不是 `7 9`。
数组排序后,也可以使用 `upper_bound(a, a + n, x) - a` 得到 的数值。( )
正确答案正确
`upper_bound(a, a + n, x)` 返回有序区间中第一个严格大于 `x` 的元素指针;减去首地址 `a` 就得到其下标。若不存在,该返回值为 `a+n`,对应程序初值 `p=n`。
当输入 `8 7 3 4 4 5 5 6 6 7` 时,程序输出为( )。
正确答案D
排序后最大元素仍是 7,没有元素严格大于 `x=7`,所以二分结束时 `p=n=8`。由于 `p < n` 不成立,程序输出 `INF=10^8-1=99999999`,即 `8 99999999`。
对于输入的 个数的序列,下列说法中正确的是( )。
正确答案D
程序读入数组后先执行 `sort(a, a+n, less<int>())`,再进行二分查找,因此原输入可以递增、递减或无序。三种输入顺序都会被统一排成升序。
(二叉树层序遍历)给定一棵以结点 1 为根的二叉树。结点编号为 ,输入每个结点的左右孩子编号,0 表示对应孩子不存在。请按层序输出所有结点,并统计叶结点数量。保证 ,输入构成一棵合法二叉树。
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 | }① 处应填( )。
q.push(0)q.push(n)q.push(1)q.pop()正确答案C
根结点编号为 1,层序遍历开始前应把根结点加入队列,即执行 `q.push(1)`。
② 处应填( )。
leftChild[u] == 0leftChild[u] != 0u != 0rightChild[u] != 0正确答案B
只有左孩子存在,即 `leftChild[u] != 0` 时,才能把它加入队列。
③ 处应填( )。
q.push(u)q.push(leftChild[u])q.push(rightChild[u])q.pop()正确答案C
条件已经确认右孩子存在,因此应执行 `q.push(rightChild[u])`。
④ 处应填( )。
leftChild[u] != 0rightChild[u] != 0leftChild[u] == rightChild[u]leftChild[u] == 0 && rightChild[u] == 0正确答案D
二叉树中的叶结点没有左孩子也没有右孩子,因此两个孩子编号都应为 0。
⑤ 处应填( )。
nleavesq.size()u正确答案B
变量 `leaves` 在遍历过程中累计叶结点数量,遍历结束后应输出它。
(网格路径计数)给定一个 的网格,其中 `#` 表示障碍,`.` 表示可通行。只能从 向下或向右移动,求到达 的路径数。保证起点和终点可通行,答案不超过 `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 | }① 处应填( )。
-1nm1正确答案D
起点到自身有一条空路径,因此应初始化 `dp[1][1]=1`。
② 处应填( )。
i < ni <= ni <= mi < m正确答案B
网格共有 n 行且下标从 1 开始,所以外层循环条件是 `i<=n`。
③ 处应填( )。
g[i][j] == '.'g[i - 1][j] == '#'g[i][j - 1] == '#'g[i - 1][j - 1] == '#'正确答案C
第 i 行字符串使用从 0 开始的列下标,所以格子 对应 `g[i][j-1]`;等于 `#` 时为障碍。
④ 处应填( )。
dp[i][j] + 1dp[i - 1][j] + dp[i][j - 1]dp[i - 1][j - 1]max(dp[i - 1][j], dp[i][j - 1])正确答案B
到达当前格的最后一步只能来自上方或左方,因此路径数为两者路径数之和。
⑤ 处应填( )。
dp[n][m]dp[1][1]dp[m][n]n + m正确答案A
`dp[i][j]` 表示到达 的路径数,目标格答案就是 `dp[n][m]`。