一、单项选择题
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
试卷解析 · 理解每一步
CSPJ-2026-R1-Mock-3
试卷解析总览,可直接查看每题答案与解析。
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
在计算机内部,传送、存储和加工处理数据或指令都是以( )形式进行的。
正确答案A
计算机内部的数字电路用两个稳定状态表示信息,因此数据和指令都以二进制码传送、存储和处理。
计算机的软件系统通常分为( )。
正确答案C
计算机软件系统通常分为系统软件和应用软件两大类。系统软件负责管理资源并为应用提供运行环境。
执行 `int x = 5; cout << (x << 2);` 后,输出结果是( )。
正确答案C
正整数 5 左移 2 位相当于乘以 ,结果为 20。
一棵二叉树的中序遍历序列为 DGBAECHF,后序遍历序列为 GDBEHFCA,则前序遍历序列为( )。
正确答案B
后序序列末尾确定根为 A。结合中序与后序可依次还原左子树前序为 BDG、右子树前序为 CEFH,所以整树前序为 ABDGCEFH。
执行下面代码后,字符串 `t` 的值为( )。
string s = "cspj";
string t = s.substr(1, 2);正确答案B
`substr(1,2)` 从下标 1 开始取 2 个字符,即 `s`、`p`,所以得到 `sp`。
计算机网络最主要的优点是( )。
正确答案B
计算机网络把分散的计算机和设备连接起来,最主要的优势是共享硬件、软件和数据等资源。
下列 4 个不同进制表示的数中,最大的一个数是( )。
正确答案C
四个数换算成十进制分别为 220.1、219.5、220.125、220.0625,因此八进制的 最大。
使用命令 `g++ a.cpp -o a` 编译成功后,源代码文件仍然是( )。
正确答案A
`a.cpp` 是输入的源代码文件,`-o a` 指定生成的可执行文件名为 `a`,源文件名称不变。
一般来说,在 TCP/IP 协议族中 IP 提供的服务属于( )。
正确答案D
IP 协议负责寻址与分组转发,属于 TCP/IP 的网络层。
执行下面代码后,`a` 的值为( )。
void add(int &x) { x += 3; }
int a = 4;
add(a);正确答案C
形参 `x` 是 `a` 的引用,函数中的加 3 会直接修改 `a`,所以结果为 7。
一个栈的输入顺序为 1, 2, 3, 4, 5,下列序列中可能是栈的输出序列的是( )。
正确答案C
序列 21543 可通过依次压入 1、2 后弹出 2、1,再压入 3、4、5 后弹出 5、4、3 得到。
对无权图进行广度优先搜索时,用来保存待访问顶点的典型数据结构是( )。
正确答案D
BFS 按发现先后依次扩展顶点,需要先进先出的队列保存待访问顶点。
函数定义如下,`f(5)` 的返回值是( )。
int f(int n) {
if (n <= 0) return 0;
return n + f(n - 2);
}正确答案C
`f(5)=5+f(3)=5+3+f(1)=5+3+1+f(-1)=9`。
下列排序算法中,最适合对大量取值范围很小的非负整数进行线性时间排序的是( )。
正确答案D
当值域很小时,计数排序可统计每个值的出现次数,时间复杂度为 。
一个无向图有 6 个顶点、9 条边,则所有顶点的度数之和为( )。
正确答案A
无向图中每条边对两个端点的度数各贡献 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 | }(1 分)外层循环第 轮结束后,子数组 `a[0..i]` 一定按严格递减顺序排列。( )
正确答案错误
程序执行的是升序插入排序,且相等元素可以并列,因此子数组不会按严格递减顺序排列,本说法错误。
(1 分)将条件 `a[j] > key` 保持不变时,这个插入排序是稳定的。( )
正确答案正确
只有前面的元素严格大于 `key` 时才会移动;相等元素不会越过彼此,所以排序稳定。
若输入序列本来已经按非递减顺序排列,则 `moves` 的最终值为 0。( )
正确答案正确
已有序时每一轮都有 `a[j] <= key`,内层循环不会执行,因此没有元素后移,`moves=0`。
若输入为 `5 5 4 3 2 1`,程序先输出 `1 2 3 4 5`,下一行输出 10。( )
正确答案正确
完全逆序的 5 个数共有 个逆序对;插入排序每消除一个逆序对移动一次,因此输出的移动次数是 10。
若把第 11 行的 `a[j] > key` 改为 `a[j] < key`,其他代码不变,程序将把序列按( )排列。
正确答案C
条件改为前面元素小于 `key` 时向后移动,相当于把较大的 key 插到前面,最终得到非递增序列。
该程序在最坏情况下的时间复杂度是( )。
正确答案D
逆序输入时,第 i 轮最多移动 i 个元素,总次数为 。
下面的程序判断一个只包含字符 `(` 和 `)` 的字符串是否为合法括号序列。
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 | }程序使用栈保存尚未匹配的左括号。( )
正确答案正确
遇到左括号时执行 `st.push(c)`,遇到可匹配的右括号时弹出一个左括号,因此栈保存的是尚未匹配的左括号。
输入为 `)` 时,程序输出 `YES`。( )
正确答案错误
处理第一个右括号时栈为空,程序把 `ok` 设为 false 并退出循环,所以输出 `NO`。
输入为 `(()())` 时,程序输出 `YES`。( )
正确答案正确
扫描过程中每个右括号都能与最近的未匹配左括号配对,结束时栈为空,因此输出 `YES`。
若删去第 20 行 `if (!st.empty()) ok = false;`,某些原本应输出 `NO` 的输入会错误地输出 `YES`。( )
正确答案正确
例如输入 `((` 时扫描途中不会遇到空栈右括号,但结束时仍有两个左括号未匹配;删去收尾检查就会误判为合法。
若输入为 `())(`,程序输出( )。
正确答案A
前两个字符完成一次匹配,第三个字符是右括号且此时栈为空,程序立即判定非法并输出 `NO`。
长度为 的输入使栈达到最大规模时,程序的额外空间复杂度为( )。
正确答案B
当输入包含 n 个左括号时,栈中最多保存 n 个字符,所以额外空间为 。
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 | }`main()` 函数里的 `for` 循环的作用是求出 的所有因数。
正确答案错误
主函数循环只枚举从 到 2 的因数,没有把 1 加入数组,因此并未求出 的所有因数。
该程序的作用是对 进行素因数分解。
正确答案错误
递归枚举的是把 写成若干个大于 1 的因数乘积的方案,因子不要求都是质数,所以不是单纯的素因数分解。
去掉 `printf("%3d", a[k]);` 中的 `3` 对程序没有影响。
正确答案错误
`%3d` 指定最小字段宽度为 3;去掉 3 会改变数字前的补空格,从而改变输出格式。
去掉 `if (n % x[k] == 0)` 对程序有影响。
正确答案正确
递归参数 `n` 会不断除去已选因数,此时剩余值未必还能被后续的 `x[k]` 整除;删除判断会进入非法分解,因此会影响程序。
如果输入为 2,那么输出为( )。
正确答案A
输入 2 时数组中只有因数 2,递归选择 2 后剩余值为 1,于是输出唯一一行 `2`。
如果输入为 72,那么输出的非回车字符有( )行。
正确答案C
程序对 72 枚举出 16 种非增因数乘积分解方案,因此共有 16 行非空输出。
输入 个整点在平面上的坐标。每个点可以控制所有位于它左下方的点(即 、 坐标都比它小的点),它可以控制的点的数目称为“战斗力”。依次输出每个点的战斗力,最后输出战斗力最高的点的编号(如果若干个点的战斗力并列最高,则输出编号最大的那个)。
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 | }① 处应填( )。
01iINT_MAX正确答案A
每个点的战斗力都应从 0 开始累计,所以处理第 个点前应令 `f[i] = 0`。
② 处应填( )。
y[j] <= y[i]y[j] < y[i]y[j] > y[i]y[j] >= y[i]正确答案B
点 位于点 左下方要求两个坐标都严格更小;已有 `x[j] < x[i]`,还需 `y[j] < y[i]`。
③ 处应填( )。
ans = if[i]++f[i]--ans++正确答案B
每发现一个满足条件的点 ,就应把当前点 的战斗力加 1,即执行 `f[i]++`。
④ 处应填( )。
f[i] > max_ff[i] >= max_ff[i] < max_ff[i] <= max_f正确答案B
需要选择最大战斗力;并列时取编号最大的。由于 从小到大枚举,条件应为 `f[i] >= max_f`,相等时也更新。
⑤ 处应填( )。
ans++ans += max_fans = ians = max_f正确答案C
更新最大战斗力时,应同步记录当前点编号,所以填 `ans = i`。
输入两个正整数 (,),在 中任取 个数,按字典序从小到大输出所有这样的排列。
样例输入:
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 | }① 处应填( )。
falsetrue1-1正确答案A
每轮输出当前排列后,先假设不存在下一排列,令 `flag = false`;只有成功找到可增大的位置时才重新设为 true。
② 处应填( )。
used[i] = truedata[i] = iused[data[i]] = trueused[data[i]] = false正确答案D
尝试增大第 位前,应先释放当前值,使其可在后续位置重新使用,因此执行 `used[data[i]] = false`。
③ 处应填( )。
jitruefalse正确答案A
内层循环找到第一个可用的更大值 `j` 后,应令 `data[i] = j`。
④ 处应填( )。
nmij正确答案A
第 位增大后,后续各位要按从小到大选择整个值域 到 中尚未使用的数,所以循环上界填 `n`。
⑤ 处应填( )。
return 0exitcontinuebreak正确答案D
成功构造出下一排列后应跳出从后向前寻找位置的 `for` 循环,返回 `while` 顶部输出新排列,因此填 `break`。