一、单项选择题
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
试卷解析 · 理解每一步
CSPJ-2026-R1-Mock-5
试卷解析总览,可直接查看每题答案与解析。
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
以下关于存储器的说法中,错误的是( )。
正确答案B
CPU 执行指令前,必须先把硬盘中的程序装入内存,不能直接从硬盘取指执行。RAM 断电丢失数据、内存通常快于外存、ROM 为只读存储器均是正确描述。
对于变量 `a = 7, b = 4`,表达式 `(a ^ b) & ((~a) | b)` 的结果是( )。
正确答案D
的低三位为 111, 为 100,按位异或后得到 3;对 a 按位取反得到 -8,再与 4 按位或得到 -4。最后 3 与 -4 按位与的结果为 0。
一个 8 位有符号整数采用二进制补码表示,其可以表示的最小十进制数是( )。
正确答案B
位有符号补码的范围是 。取 ,最小值为 。
在 NOI Linux 终端中,要创建一个名为 `test` 的新目录,应该使用( )命令。
正确答案C
mkdir 用于创建目录,因此 mkdir test 会在当前路径下新建名为 test 的目录。
是正整数且在 `int` 范围内,则表达式 `(x & (x - 1)) == 0` 可以用来判断一个无符号整数 ( )。
正确答案B
会把 最低的 1 变为 0,并把其后的 0 变为 1;与 按位与后相当于清除最低的 1。正整数结果为 0 当且仅当原数只有一个 1,即 。
在平均情况下,( )算法的时间复杂度最低。
正确答案C
快速排序平均每层划分处理 个元素,递归深度平均为 ,总时间为 。冒泡、插入和选择排序的平均时间均为 。
以下代码的空间复杂度是( )。
int sum = 0;
for (int i = 0; i < n; i++) {
int temp = i * 2;
sum += temp;
}正确答案A
循环只使用 sum、i、temp 等固定数量的标量变量,没有随 增长的数组或递归栈,因此额外空间为 。
一个项目团队有 12 名成员,任意两名成员之间都有直接合作关系。若用顶点表示成员、用边表示直接合作关系,则最准确描述该图结构的是( )。
正确答案B
任意两名成员之间都有直接合作关系,意味着任意两个顶点之间都有一条边,因此该图恰好是 12 个顶点的完全图 。
一个栈的入栈序列为 1,2,3,4,5,6。出栈序列中,3 是第二个出栈的元素。出栈序列( )是不可能的。
正确答案B
序列 B 弹出 2、3、4 后,为先弹出 6 必须把 5、6 依次压栈;弹出 6 后栈顶仍是 5,不可能越过 5 先弹出 1。因此该序列不可能出现。
5 个男生和 3 个女生站成一排,要求女生不相邻,且第一个和最后一个位置必须是男生,不同的排法有( )种。
正确答案C
先排列 5 个男生有 种。两端必须是男生且女生不相邻,所以 3 个女生只能放入男生之间的 4 个空隙,选 3 个空隙并排列女生,共 种。
已知二叉树的中序遍历序列为 DBEAC,后序遍历序列为 DEBCA,则前序遍历序列为( )。
正确答案B
后序末尾 A 是根;中序 DBEAC 将左子树分为 DBE、右子树分为 C。左子树后序为 DEB,故其根为 B,左右孩子分别为 D、E,前序得到 ABDEC。
用数组存储完全二叉树,按从上到下、从左到右的顺序编号(从 1 开始),则节点 的左子节点是( )。
正确答案A
从 1 开始编号时,节点 的两个孩子编号依次为 和 ,因此左子节点是 。
以下关于 CPU(中央处理器)的描述中,正确的是( )。
正确答案D
CPU 承担指令解释、算术逻辑运算和整机控制,是计算机的核心处理部件。它主要由运算器、控制器和寄存器等组成,性能还受架构、缓存、核心数等多种因素影响。
学校有 门课程,部分课程有先修关系(必须先修 A 才能修 B)。现要判断课程安排是否合理,有没有循环依赖。这对应图论中的( )问题。
正确答案B
把课程作为顶点、先修关系作为有向边,合理的修课顺序就是该图的拓扑序。若拓扑排序无法处理全部 个顶点,则图中存在环,也就是循环依赖。
某哈夫曼树有 8 个叶节点,该树总共有( )个节点。
正确答案B
哈夫曼树是每个内部节点都有两个孩子的满二叉树。叶节点数为 时,内部节点数为 ,总节点数为 。
1 | #include <iostream>
2 | using namespace std;
3 |
4 | int process(int n) {
5 | if (n == 0) return 0;
6 | return n % 2 + process(n / 2) * 10;
7 | }
8 |
9 | int main() {
10 | int num;
11 | cin >> num;
12 | int result = process(num);
13 | cout << result << endl;
14 | return 0;
15 | }输入 10 时,输出为 1010。( )
正确答案正确
process(10) 依次递归到 5、2、1、0,再按返回顺序计算:1、10、101、1010,所以最终输出 1010。
输入 1024 时,输出为 10000000000。( )
正确答案错误
数学上 会生成 10000000000,但该十进制整数大于 32 位 int 上限 2147483647。递归返回时发生有符号整数溢出,不能正常输出 10000000000。
对于任意正整数 ,`process(n)` 的输出总是一个由 0 和 1 组成的数。( )
正确答案错误
每层产生的余数确实只有 0 或 1,但函数把这些位拼成 int。输入较大时拼成的十进制整数会溢出,实际结果不再保证是只含 0、1 的有效数。
若输入 2025,则函数 `process` 被递归调用( )次(包括第一次调用)。
正确答案C
2025 连续整除 2 得到 2025、1012、506、253、126、63、31、15、7、3、1、0,共 12 个参数值。包括终止条件 process(0) 在内,递归调用 12 次。
函数 `process` 的时间复杂度是( )。
正确答案C
每次调用把 n 变为 ,到 0 需要约 层;每层只做常数次运算,所以时间复杂度为 。
程序能正常处理的最大输入值为( )。
正确答案A
process(1023) 生成 1111111111,小于 int 上限 2147483647;从 1024 起二进制表示有 11 位,拼成的十进制整数至少为 10000000000,超出 int。故能正常处理的最大输入值为 1023。
1 | #include <iostream>
2 | #include <cmath>
3 | #define MAX 100
4 | using namespace std;
5 | int digits[MAX + 9];
6 | void solve(int a, int b, int precision) {
7 | if (b == 0) {
8 | cout << "Error: Division by zero!" << endl;
9 | return;
10 | }
11 | if (precision > MAX) precision = MAX;
12 | if (precision < 0) precision = 0;
13 |
14 | bool negative = (a < 0 && b > 0) || (a > 0 && b < 0);
15 | a = abs(a);
16 | b = abs(b);
17 | digits[0] = a / b;
18 | int remainder = a % b;
19 |
20 | for (int i = 1; i <= precision + 1; i++) {
21 | remainder *= 10;
22 | digits[i] = remainder / b;
23 | remainder %= b;
24 | }
25 |
26 | if (digits[precision + 1] >= 5) {
27 | digits[precision]++;
28 | for (int i = precision; i >= 1; i--) {
29 | if (digits[i] >= 10) {
30 | digits[i] -= 10;
31 | digits[i - 1]++;
32 | } else {
33 | break;
34 | }
35 | }
36 | }
37 |
38 | if (negative) cout << "-";
39 | cout << digits[0] << '.';
40 | for (int i = 1; i <= precision; i++) {
41 | cout << digits[i];
42 | }
43 | cout << endl;
44 | }
45 |
46 | int main() {
47 | int a, b, prec;
48 | cin >> a >> b >> prec;
49 | solve(a, b, prec);
50 | return 0;
51 | }
52 | // 所有输入数据的绝对值均小于 1000程序输出结果保留指定的小数位数,同时实现四舍五入,小数位的数量等于输入变量 `prec` 的值。( )
正确答案错误
程序会先把 precision 限制到 :大于 100 时只输出 100 位,小于 0 时按 0 位处理。因此输出小数位数不一定等于原始输入 prec,虽然有效范围内会利用下一位完成四舍五入。
若输入 `2025 25 0`,程序会输出 81。( )
正确答案错误
且余数为 0;precision 为 0 时小数数字循环不执行,但第 39 行仍会输出小数点。因此实际输出是 81.,不是 81。
若将程序中的 `solve(a, b, prec);` 替换成 `cout << fixed << setprecision(prec) << (1.0 * a / b) << endl;`,其他部分不变,则当 `prec` 的输入值在 区间时,输出结果是一样的。( )
正确答案错误
取 prec=0 即可反例:原 solve 会无条件输出 digits[0] 后的点号,而 fixed 与 setprecision(0) 只输出取整后的数,不带小数点。故即使 prec 限制在 ,两种输出也不总相同。
如果输入 `2026 26 4`,则输出的结果是( )。
正确答案C
的整数部分为 77、余数为 24,依次产生小数位 9、2、3、0,下一位为 7。因为第 5 位不小于 5,第 4 位由 0 进为 1,输出 77.9231。
如果输入的数据为 `2026 0 -6`,下列说法中正确的是( )。
正确答案B
solve 首先判断 b==0,输出 Error: Division by zero! 后立即 return,因此不会执行 a/b 或 a%b,也不会输出具体数值。prec=-6 对这一分支没有影响。
1 | #include <iostream>
2 | #include <vector>
3 | using namespace std;
4 |
5 | int bSearch(vector<int>& a, int target) {
6 | int left = 0, right = a.size() - 1;
7 |
8 | while (left <= right) {
9 | int mid = left + (right - left) / 2;
10 | if (a[mid] == target) {
11 | return mid;
12 | } else if (a[mid] > target) {
13 | left = mid + 1;
14 | } else {
15 | right = mid - 1;
16 | }
17 | }
18 | return -1;
19 | }
20 |
21 | int main() {
22 | int n, x;
23 | cin >> n >> x;
24 |
25 | vector<int> a(n);
26 | for (int i = 0; i < n; i++) cin >> a[i];
27 | int ans = bSearch(a, x);
28 | cout << (ans != -1 ? ans : -1) << endl;
29 | return 0;
30 | }如果输入 `6 3 10 9 8 6 5 4`,程序会输出 -1。( )
正确答案正确
初始 mid=2,a[2]=8>3,令 left=3;随后检查下标 4 的 5 和下标 5 的 4,left 最终变为 6。此时 left>right,函数返回 -1。
该程序使用二分法,在单调不升数组中查找某个数在整个数组中排在第几个位置。( )
正确答案错误
程序确实在单调不升数组中二分查找,但找到后直接返回 mid,即从 0 开始的数组下标。它没有统计比目标大的元素数,也没有转换成通常从 1 开始的名次。
要保证正常查找功能,输入必须从大到小排列,并且数值要连续。( )
正确答案错误
分支方向要求数组单调不升,但相邻数值可以相等,也可以有任意大小的间隔。例如 10、7、3 仍满足该二分查找的前提,不需要数值连续。
如果输入 `10 4 20 17 15 11 10 9 8 6 5 3`,程序会输出( )。
正确答案D
查找 4 时依次检查下标 4、7、8、9,对应值为 10、6、5、3。前三个值大于 4 使 left 右移,最后 3 小于 4 使 right 变为 8,区间为空后返回 -1。
如果输入单调不升数组,被查找的数值出现过多次,则程序输出是( )。
正确答案C
一旦 a[mid]==target,函数立即返回 mid,之后不再向左或向右收缩边界。因此返回哪个重复元素取决于二分过程中首先命中的 mid,不保证是最小或最大下标。
如果输入 `4 4 4 4 4 4`,程序会输出( )。
正确答案B
输入表示 n=4、target=4,数组四项也全为 4。初始 left=0、right=3,第一次计算 mid=0+(3-0)/2=1,立即匹配并返回 1。
给定一个整数数组和一个整数 ,程序找出数组中 个不相邻元素(即任意两个被选元素在数组中不相邻)的最大和。
1 | #include <iostream>
2 | #include <vector>
3 | #include <algorithm>
4 | using namespace std;
5 |
6 | int solve(vector<int>& nums, int k) {
7 | int n = ①;
8 | vector<vector<int>> dp(②);
9 |
10 | for (int i = 1; i <= n; i++) {
11 | for (int j = 1; j <= k; j++) {
12 | if (j == 1) {
13 | dp[i][j] = max(③);
14 | } else {
15 | dp[i][j] = max(dp[i - 1][j], ④);
16 | }
17 | }
18 | }
19 | return ⑤;
20 | }
21 |
22 | int main() {
23 | int n, k;
24 | cin >> n >> k;
25 | vector<int> nums(n);
26 | for (int i = 0; i < n; i++) cin >> nums[i];
27 | cout << solve(nums, k) << endl;
28 | return 0;
29 | }① 处应填( )。
nums.size() - 1nums.size()nums.length() - 1nums.length()正确答案B
后续循环按 i=1 到 n 处理 nums 的全部元素,所以 n 应等于 nums.size()。vector 没有 length() 成员,且减 1 会漏掉最后一个元素。
② 处应填( )。
n, vector<int>(k, 0)n, vector<int>(k + 1, 0)n + 1, vector<int>(k, 0)n + 1, vector<int>(k + 1, 0)正确答案D
dp[i][j] 表示在前 i 个元素中选择 j 个不相邻元素的最大和;状态需要覆盖 和 。因此二维表应开为 n+1 行、每行 k+1 列并初始化为 0。
③ 处应填( )。
dp[i - 1][j], nums[i - 1]dp[i][j], nums[i - 1]dp[i - 1][j - 1] + nums[i - 1]dp[i][j] + nums[i - 1]正确答案A
当 j=1 时,第 i 个元素有“不选”和“选”两种情况:不选沿用 dp[i-1][1],选它的和就是 nums[i-1],因此两者取最大值。若数组允许全负数且必须恰选 1 个,原框架还需把不可达状态初始化为负无穷。
④ 处应填( )。
dp[i - 1][j], nums[i - 1]dp[i][j], nums[i - 1]dp[i - 2][j - 1] + nums[i - 1]dp[i][j] + nums[i - 1]正确答案C
在可达状态中,若选择 nums[i-1],其余 j-1 个只能来自前 i-2 个元素,得到 dp[i-2][j-1]+nums[i-1];再与 dp[i-1][j] 取最大值。原框架还应避免在 i=1、j>1 时访问 dp[-1][j-1],但这不改变空④的转移项。
⑤ 处应填( )。
dp[n - 1][k - 1]dp[n][k - 1]dp[n - 1][k]dp[n][k]正确答案D
程序处理完全部 n 个元素后,需要得到“从前 n 个元素中选择 k 个”的最大和,对应目标状态 dp[n][k]。
给定一条长度为 的线段( 为整数),以及 个整数区间,每个区间有整数起始位置和结束位置。程序的目标是选择最少数量的区间,使得这些区间完全连续覆盖整个线段 。如果无法完全覆盖,则输出 -1。
1 | #include <iostream>
2 | #include <algorithm>
3 | using namespace std;
4 | const int N = 100005;
5 |
6 | struct Interval { int s, e; } ivl[N];
7 | bool cmp(Interval a, Interval b) {
8 | return a.s < b.s || (①);
9 | }
10 |
11 | int main() {
12 | int L, n;
13 | cin >> L >> n;
14 |
15 | for (int i = 0; i < n; i++) {
16 | cin >> ivl[i].s >> ivl[i].e;
17 | }
18 | ②
19 |
20 | int curr = 0;
21 | int cnt = 0;
22 | int i = 0;
23 |
24 | while (curr < L) {
25 | int mx_reach = curr;
26 | while (③) {
27 | if (ivl[i].e > mx_reach) {
28 | mx_reach = ivl[i].e;
29 | }
30 | i++;
31 | }
32 |
33 | if (④) {
34 | cout << -1 << endl;
35 | return 0;
36 | }
37 | cnt++;
38 | ⑤
39 | }
40 |
41 | cout << cnt << endl;
42 | return 0;
43 | }① 处应填( )。
a.s == b.s && a.e < b.ea.s == b.s && a.e <= b.ea.s == b.s && a.e != b.ea.s == b.s && a.e >= b.e正确答案A
cmp 先按起点 a.s 升序排列;当起点相同时,应再用 a.e<b.e 按终点升序排列,所以补充条件为 a.s==b.s 且 a.e<b.e。严格小于也满足 sort 所需的严格弱序。
② 处应填( )。
sort(ivl, ivl + n);sort(ivl, ivl + n, cmp);sort(ivl + 1, ivl + 1 + n);sort(ivl + 1, ivl + 1 + n, cmp);正确答案B
ivl 中的 n 个区间存放在下标 ,sort 使用左闭右开区间,因此范围应为 [ivl,ivl+n)。同时必须传入 cmp 才能按结构体的起点、终点排序。
③ 处应填( )。
i < n && ivl[i].s > curri < n && ivl[i].s >= curri < n && ivl[i].s <= curri < n && ivl[i].s < curr正确答案C
当前已经连续覆盖到 curr,下一步必须考察所有起点 ivl[i].s<=curr 的区间,并从中选择终点最大的一个。起点大于 curr 的区间会在 curr 后留下空隙,不能接续覆盖。
④ 处应填( )。
i < ni > nmx_reach < currmx_reach == curr正确答案D
mx_reach 初始等于 curr;扫描所有起点不大于 curr 的区间后,若 mx_reach 仍等于 curr,说明没有区间能把覆盖右端向前推进,区间链在此处中断,只能输出 -1。
⑤ 处应填( )。
curr = mx_reach;curr += mx_reach;curr = intervals[i].e;curr += intervals[i].e - intervals[i].s + 1;正确答案A
内层循环已在所有可衔接区间中求出最远终点 mx_reach;选定这一个区间后,连续覆盖的右端应直接更新为 curr=mx_reach,并把 cnt 增加 1。