一、单项选择题
共 15 题,每题 2 分,共 30 分。每题有且仅有一个正确选项。
试卷解析 · 理解每一步
CSPJ-2026-R1-Mock-AI-3
试卷解析总览,可直接查看每题答案与解析。
共 15 题,每题 2 分,共 30 分。每题有且仅有一个正确选项。
在 Linux 终端中,若要把源文件 main.cpp 编译为名为 train 的可执行文件,正确的命令是( )。
正确答案A
g++ 的 -o 选项指定输出文件名,因此源文件在前,-o 后写 train。重定向符号 > 只重定向标准输出,不能代替 -o。
640 个二进制位恰好占用( )字节。
正确答案C
1 字节等于 8 位,所以 640÷8=80 字节。
二进制数 (11010110)₂ 对应的十六进制数是( )。
正确答案B
从右向左每 4 位分组:1101 对应 D,0110 对应 6,所以结果为 D6。
以下 C++14 程序片段的输出是( )。
int a = 17, b = 5;
cout << (a / b + a % b * 2 > 8);正确答案D
整数除法 17/5=3,取模 17%5=2,先算乘法得到 2×2=4,再得 3+4=7。关系表达式 7>8 为 false,cout 输出 0。
以下 C++14 程序的输出是( )。
void change(int x, int &y) {
x += 2;
y += x;
}
int main() {
int a = 3, b = 4;
change(a, b);
cout << a << " " << b;
}正确答案C
x 是值形参,函数内变为 5 但不改变 a;y 是 b 的引用,执行 y+=x 后 b=4+5=9,因此输出 3 9。
以下 C++14 程序片段的输出是( )。
vector<int> v = {2, 5};
v.push_back(7);
v[0] += v.back();
v.pop_back();
cout << v.size() << " " << v[0];正确答案A
push_back 后为 {2,5,7},v[0] 加上末元素后变为 9;pop_back 删除 7,剩余两个元素,所以输出 2 9。
栈 s 和队列 q 初始均为空。执行以下代码后的输出是( )。
s.push(3); s.push(7);
q.push(4); q.push(6);
cout << s.top() + q.front();
s.pop(); q.pop();
cout << " " << s.top() + q.front();正确答案B
第一次访问栈顶 7 与队首 4,和为 11。各弹出一个元素后,栈顶为 3、队首为 6,和为 9。
一棵完全二叉树按层序从 1 开始给结点编号,共有 26 个结点。编号为 13 的结点( )。
正确答案D
1 起始编号时,结点 i 的左右孩子编号分别为 2i 和 2i+1。对 i=13,26 存在而 27>26 不存在,因此只有左孩子 26。
某无向简单图的邻接矩阵如下。顶点 4 的度数为( )。
0 1 0 1 0
1 0 1 1 0
0 1 0 0 1
1 1 0 0 1
0 0 1 1 0正确答案C
顶点 4 对应第 4 行,其中第 1、2、5 列为 1,共连接 3 条边,所以度数为 3。
当 n 为正整数时,以下代码片段的时间复杂度是( )。
for (int i = 1; i <= n; i *= 2)
for (int j = 0; j < n; ++j)
++cnt;正确答案B
外层 i 每次乘 2,共执行 O(log n) 轮;每轮内层执行 n 次,总次数为 O(n log n)。
关于从小到大的直接插入排序,下列说法正确的是( )。
正确答案A
直接插入排序维护一个已排序前缀,把当前元素插入适当位置;逆序输入会产生约 n²/2 次移动,最坏复杂度为 O(n²)。B 描述选择排序,D 描述冒泡排序。
调用 f(7) 时,函数 f 被调用的总次数(包含第一次调用和基例调用)是( )。
void f(int n) {
if (n == 0) return;
f(n - 1);
}正确答案D
调用参数依次为 7,6,5,4,3,2,1,0,共 8 次。
使用欧几里得算法计算 gcd(414,276),结果是( )。
正确答案C
414 mod 276=138,276 mod 138=0,因此最大公因数是最后一个非零余数 138。
数组 a 的下标从 1 开始,p[i]=a[1]+⋯+a[i],且 p[0]=0。区间 a[2]+⋯+a[5] 应表示为( )。
正确答案B
p[5] 含 a[1] 到 a[5],减去 p[1]=a[1] 后恰好剩 a[2] 到 a[5]。
从 7 名学生中选出 3 人组成小组,并在小组内指定 1 名组长和 1 名记录员,且两种角色不能由同一人担任。不同方案共有( )种。
正确答案A
先选 3 人有 C(7,3)=35 种,再从组内选组长有 3 种、选不同的记录员有 2 种。乘法原理得 35×3×2=210。
假设 1≤n≤100000,且所有输入整数绝对值不超过 1000。阅读程序并回答问题。
1 | #include <bits/stdc++.h>
2 | using namespace std;
3 | int main() {
4 | int n;
5 | cin >> n;
6 | vector<int> a(n);
7 | for (int i = 0; i < n; ++i) cin >> a[i];
8 | int best = 1, cur = 1;
9 | int turns = 0;
10 | for (int i = 1; i < n; ++i) {
11 | if (a[i] > a[i - 1]) {
12 | ++cur;
13 | } else {
14 | best = max(best, cur);
15 | cur = 1;
16 | }
17 | if (i >= 2) {
18 | int x = a[i - 1] - a[i - 2];
19 | int y = a[i] - a[i - 1];
20 | if (x * y < 0) ++turns;
21 | }
22 | }
23 | best = max(best, cur);
24 | cout << best << " " << turns << "\n";
25 | }若 n=1,则程序输出的第一个数为 1。
正确答案正确
循环不会执行,best 初值为 1,末尾更新仍为 1,因此第一个输出为 1。
每次处理完下标 i 后,cur 表示以 a[i] 结尾的连续严格递增段长度。
正确答案正确
若 a[i]>a[i-1],原递增段延长 1;否则以 a[i] 重新开始长度为 1 的段。因此该不变量始终成立。
程序的时间复杂度是 O(n²)。
正确答案错误
输入循环和主循环都只线性扫描一次,每轮工作为常数,总时间复杂度为 O(n),不是 O(n²)。
输入如下时,程序输出是( )。
8
1 3 5 4 2 2 6 9正确答案C
最长连续严格递增段为 1,3,5 或 2,6,9,长度均为 3。相邻差依次为 +2,+2,-1,-2,0,+4,+3,仅 +2 到 -1 的乘积小于 0,所以 turns=1。
当某个中间元素两侧的相邻差都不为 0 时,该元素使 turns 增加的充分必要条件是( )。
正确答案B
turns 增加当且仅当前后两个差的乘积小于 0,即符号相反;这正对应中间元素是严格局部极大值或严格局部极小值。
若输入序列含 6 个严格递减且互不相等的整数,则程序输出是( )。
正确答案A
每一步都不满足递增条件,cur 每次重置为 1,所以 best=1;所有相邻差都为负,任意相邻两个差乘积为正,turns=0。
输入满足 1≤n,m≤30,起点坐标使用从 0 开始的行列编号。相邻格仅指上、下、左、右四个方向。阅读程序并回答问题。
1 | #include <bits/stdc++.h>
2 | using namespace std;
3 | const int N = 35;
4 | int h[N][N], dista[N][N];
5 | int main() {
6 | int n, m, sx, sy;
7 | cin >> n >> m >> sx >> sy;
8 | for (int i = 0; i < n; ++i)
9 | for (int j = 0; j < m; ++j)
10 | cin >> h[i][j];
11 | queue<pair<int, int>> q;
12 | for (int i = 0; i < n; ++i)
13 | for (int j = 0; j < m; ++j)
14 | dista[i][j] = -1;
15 | dista[sx][sy] = 0;
16 | q.push({sx, sy});
17 | int dx[4] = {-1, 1, 0, 0};
18 | int dy[4] = {0, 0, -1, 1};
19 | while (!q.empty()) {
20 | pair<int, int> cur = q.front();
21 | q.pop();
22 | int x = cur.first, y = cur.second;
23 | for (int k = 0; k < 4; ++k) {
24 | int nx = x + dx[k], ny = y + dy[k];
25 | if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
26 | if (dista[nx][ny] != -1) continue;
27 | if (abs(h[nx][ny] - h[x][y]) > 2) continue;
28 | dista[nx][ny] = dista[x][y] + 1;
29 | q.push({nx, ny});
30 | }
31 | }
32 | int cnt = 0, farthest = 0;
33 | for (int i = 0; i < n; ++i)
34 | for (int j = 0; j < m; ++j)
35 | if (dista[i][j] != -1) {
36 | ++cnt;
37 | farthest = max(farthest, dista[i][j]);
38 | }
39 | cout << cnt << " " << farthest << "\n";
40 | }程序在把一个格子加入队列之前就写入其 dista 值,这可以避免同一格子被重复加入队列。
正确答案正确
未访问格的 dista 为 -1;入队前立即改成非负值,之后其他相邻格再检查它时会直接跳过,因此每格至多入队一次。
两个四方向相邻格子的高度差绝对值恰好为 2 时,程序允许从其中一个移动到另一个。
正确答案正确
程序只在高度差绝对值大于 2 时跳过;恰好等于 2 不会跳过,因此允许双向移动。
对每个可达格子,dista 中记录的是从起点出发、按程序移动规则到达该格子的最少步数。
正确答案正确
每条移动边代价均为 1,队列按距离从小到大分层扩展;格子首次入队时得到的距离即最短距离。
输入如下时,程序输出是( )。
3 4 0 0
1 2 4 9
2 4 5 8
7 6 5 7正确答案B
所有 12 个格子均可达。最远的 (0,3) 可沿 (0,0)→(0,1)→(0,2)→(1,2)→(2,2)→(2,3)→(1,3)→(0,3) 到达,共 7 步,且不存在更短合法路径。
忽略固定上界 N,程序关于 n、m 的时间复杂度是( )。
正确答案C
每个格子至多入队一次,每次只检查 4 个方向;初始化和汇总也各扫描一次网格,因此总时间为 O(nm)。
对下面输入,若仅把第 27 行中的常数 2 改为 3,则 cnt 比原程序增加( )。
2 4 0 0
1 4 7 10
1 1 7 10正确答案D
原阈值 2 时只能到达左侧三个高度为 1 的格子,cnt=3。阈值改为 3 后可沿顶行 1→4→7→10,并进入相应下方格子,8 格全可达,增加 8-3=5。
输入满足 1≤n≤200,1≤k≤输入中不同整数的个数。程序按结点数定义树高。阅读程序并回答问题。
1 | #include <bits/stdc++.h>
2 | using namespace std;
3 | struct Node {
4 | int v;
5 | Node *left, *right;
6 | Node(int x) : v(x), left(nullptr), right(nullptr) {}
7 | };
8 | Node* insertNode(Node* p, int x) {
9 | if (p == nullptr) return new Node(x);
10 | if (x < p->v) p->left = insertNode(p->left, x);
11 | else if (x > p->v) p->right = insertNode(p->right, x);
12 | return p;
13 | }
14 | int height(Node* p) {
15 | if (p == nullptr) return 0;
16 | return max(height(p->left), height(p->right)) + 1;
17 | }
18 | int leaves(Node* p) {
19 | if (p == nullptr) return 0;
20 | if (p->left == nullptr && p->right == nullptr) return 1;
21 | return leaves(p->left) + leaves(p->right);
22 | }
23 | void inorder(Node* p, vector<int>& out) {
24 | if (p == nullptr) return;
25 | inorder(p->left, out);
26 | out.push_back(p->v);
27 | inorder(p->right, out);
28 | }
29 | int main() {
30 | int n, k;
31 | cin >> n >> k;
32 | Node* root = nullptr;
33 | for (int i = 0; i < n; ++i) {
34 | int x;
35 | cin >> x;
36 | root = insertNode(root, x);
37 | }
38 | vector<int> order;
39 | inorder(root, order);
40 | cout << height(root) << " " << leaves(root) << " "
41 | << order[k - 1] << "\n";
42 | }输入中重复出现的数值不会在这棵二叉搜索树中生成新的结点。
正确答案正确
insertNode 只处理 x<p->v 和 x>p->v 两种情况;相等时直接返回原指针,因此重复值被忽略。
按程序中 height 的定义,只含根结点的一棵树高度为 1。
正确答案正确
根的左右空子树高度都是 0,返回 max(0,0)+1=1。
执行 inorder 后,order 中的元素严格递增。
正确答案正确
二叉搜索树满足左子树值小于根、右子树值大于根,且重复值未插入;中序遍历按左、根、右访问,所以序列严格递增。
输入如下时,程序输出是( )。
9 5
12 5 18 2 9 15 21 7 16正确答案D
建树后最长根到叶路径含 4 个结点;叶结点为 2、7、16、21,共 4 个。中序序列为 2,5,7,9,12,15,16,18,21,第 5 个数是 12。
若输入的 n 个数互不相同且严格递增,程序建树部分的最坏时间复杂度是( )。
正确答案B
严格递增输入使每个新结点都沿右孩子链走到底。第 i 次插入需 O(i) 时间,总和 1+2+⋯+(n-1)=O(n²)。
依次插入 1~7 这 7 个互不相同的整数时,下列输入顺序能使程序计算出的树高为 3 的是( )。
正确答案B
B 以 4 为根,2、6 为第二层,1、3、5、7 为第三层,树高恰为 3。A 退化为高度 7;C 和 D 都产生超过 3 层的链。
给定一个含 n 个整数的环形序列和整数 k(1≤k≤n≤100000)。要从 n 个起点中选一个,求连续 k 个元素的最大和。输入元素绝对值不超过 10^9。请补全程序。
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
long long a[N], pre[N];
int main() {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
a[①] = a[i];
}
pre[0] = 0;
for (int i = 1; i <= 2 * n; ++i)
pre[i] = ②;
long long best = LLONG_MIN;
for (int l = 1; l <= n; ++l) {
int r = ③;
long long cur = ④;
best = ⑤;
}
cout << best << "\n";
}①处应填( )。
i + ni + kn - i + 12 * i正确答案A
把原数组再复制一份到其后方,应令 a[i+n]=a[i],这样任何跨过末尾的长度 k 窗口都在线性数组中连续。
②处应填( )。
pre[i - 1] + a[i - 1]pre[i - 1] + a[i]pre[i] + a[i - 1]a[i] - pre[i - 1]正确答案B
pre[i] 表示 a[1] 到 a[i] 的和,因此递推式为 pre[i]=pre[i-1]+a[i]。
③处应填( )。
l + kl + n - 1l + k - 1(l + k) % n正确答案C
闭区间 [l,r] 含 k 个元素满足 r-l+1=k,所以 r=l+k-1。复制展开后无需取模。
为了由已经算好的 pre 数组在 O(1) 时间得到当前窗口 [l,r] 的元素和,④处应填( )。
pre[2 * n] - pre[r]pre[r] - pre[l] + a[r]pre[r] - pre[l - 1]pre[r - l + 1]正确答案C
pre[r] 包含 a[1] 到 a[r],减去窗口左侧的 a[1] 到 a[l-1],剩余部分恰为闭区间 [l,r] 的元素和。
⑤处应填( )。
max(best, cur)min(best, cur)max(best, (long long)r)best + cur正确答案A
best 始终维护已检查窗口的最大元素和,所以应用 max(best,cur) 更新。
给定 n 种正整数面值的硬币,每种硬币可使用任意次,求恰好凑出 target(1≤target≤10000)所需的最少硬币数,并输出一种方案;若无法凑出则输出 -1。请补全程序。
#include <bits/stdc++.h>
using namespace std;
const int INF = 1000000000;
int main() {
int n, target;
cin >> n >> target;
vector<int> coin(n);
for (int i = 0; i < n; ++i) cin >> coin[i];
vector<int> dp(target + 1, INF);
vector<int> last(target + 1, -1);
①;
for (int x = 1; x <= target; ++x) {
for (int j = 0; j < n; ++j) {
if (②) {
if (③) {
dp[x] = dp[x - coin[j]] + 1;
④;
}
}
}
}
if (dp[target] == INF) {
cout << -1 << "\n";
return 0;
}
cout << dp[target] << "\n";
int x = target;
while (x > 0) {
cout << coin[last[x]]
<< (x == coin[last[x]] ? '\n' : ' ');
⑤;
}
}①处应填( )。
dp[target] = 0last[0] = 0dp[0] = 0dp[0] = INF正确答案C
凑出金额 0 不需要硬币,所以状态边界是 dp[0]=0;其他金额保持 INF 表示尚不可达。
②处应填( )。
x >= coin[j] && dp[x - coin[j]] != INFx > coin[j] || dp[x - coin[j]] == INFx <= coin[j] && dp[x + coin[j]] != INFdp[x] != INF正确答案A
只有 x 不小于当前硬币面值时下标 x-coin[j] 才合法,并且该前驱金额必须可达,才能加入一枚硬币转移。
③处应填( )。
dp[x - coin[j]] < dp[x]dp[x - 1] + coin[j] < dp[x]dp[x] + 1 < dp[x - coin[j]]dp[x - coin[j]] + 1 < dp[x]正确答案D
从 x-coin[j] 的最优方案加入一枚 coin[j],候选硬币数是 dp[x-coin[j]]+1;只有候选严格更小时才更新 dp[x]。
④处应填( )。
last[j] = xlast[x] = jlast[x - coin[j]] = xlast[x] = coin[j]正确答案B
恢复方案时程序把 last[x] 当作 coin 的下标使用,因此应记录使 dp[x] 改进的硬币下标 j。
⑤处应填( )。
x += coin[last[x]]x -= last[x]x -= coin[last[x]]x = last[x]正确答案C
已经输出最后使用的硬币后,剩余金额应减去该硬币面值,即 x-=coin[last[x]];由于面值为正,循环必向 0 推进。