一、单项选择题
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
试卷解析 · 理解每一步
CSPJ-2024-R1-Mock-Luogu
试卷解析总览,可直接查看每题答案与解析。
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
C++ 是一种面向对象的程序设计语言。在 C++ 中,下面哪个关键字用于声明一个类,其缺省继承方式为 `private` 继承?( )
正确答案C
用 `class` 声明类时,未显式写出访问控制的继承默认为 `private`,因此选择 C。
下述代码实现的数据结构是( )。
int data[100], f = 1, r;
void insert(int value) {
data[++r] = value;
}
void pop() {
f++;
}正确答案C
`insert` 在尾端下标 `r` 后追加元素,`pop` 将首端下标 `f` 后移,符合队列先进先出的操作方式。
C++ 语言中,以 `0b` 开头的数为( )进制数。
正确答案A
C++ 中前缀 `0b` 或 `0B` 表示二进制整数字面量,所以选择 A。
根结点的高度为 1,高度为 5 的完全二叉树至少有( )个结点。
正确答案B
高度为 5 时,前 4 层必须填满,共有 个结点;第 5 层至少有 1 个结点,因此最少为 16。
右图所示的二叉树,其后序遍历的结果是什么?( )

正确答案D
按“左子树、右子树、根”遍历图中二叉树,依次得到 `e g d c f b a`,即 `egdcfba`。
考虑右图所示的数字电路,有关逻辑门的含义已在图中标出。高电平表示 `true`,低电平表示 `false`。当 的输入依次为低电平、高电平、高电平时,输出为( )。

正确答案A
图中先计算 ,再与 做或运算;输入为假、真、真时,结果为 ,输出高电平。
十进制数 10.375 转换为八进制数的结果为( )。
正确答案D
整数部分 ;小数部分 ,所以结果是 。
假设有一组字符 `{g,h,i,j,k,l}`,它们对应的频率分别为 8%、14%、17%、20%、23%、18%。请问以下哪个选项是字符 `g,h,i,j,k,l` 分别对应的一组哈夫曼编码?( )
正确答案C
合并最小频率可得码长:`g,h,i,l` 为 3,`j,k` 为 2;选项 C 的码字既满足这些码长又互不为前缀。
中缀表达式 `((6 - 3) * 2 + 7) / (5 ^ (3 * 4 + 2))` 对应的后缀表达式为( )。
/ + * - 6 3 2 7 ^ 5 + * 3 4 26 3 2 - * 7 + 5 3 4 * 2 + ^ /6 3 - 2 * 7 + 5 3 4 * 2 + ^ /6 3 - 2 * 7 + 3 4 * 2 + 5 ^ /正确答案C
先分别处理括号和运算优先级,得到 `6 3 - 2 * 7 + 5 3 4 * 2 + ^ /`,对应选项 C。
将 3 个相同的红球和 3 个相同的黑球装入三个不同的袋中,每袋均装 2 个球,则不同的装法总数为( )。
正确答案A
令每袋红球数为 0、1 或 2,总和为 3;满足条件的有序三元组共有 7 个,黑球数随之唯一确定。
从 2 至 8 的 7 个整数中随机取 2 个不同的数,这两个数互质的概率为( )。
正确答案D
从 2 到 8 任选两数共有 对,其中互质的有 14 对,概率为 。
以下哪一种算法典型地使用了分治法的思想来解决问题?( )
正确答案B
快速排序通过一次划分把问题拆成两个子区间,再递归排序,典型地体现了分治思想。
奇偶校验编码是常见的校验编码方式。对于二进制编码 ,奇偶校验编码在编码的最后增加一位校验位 ,并将原编码与校验位作为整体发送。奇校验位保证 ,偶校验位保证该结果为 0。下列编码与校验位对应正确的是( )。
正确答案C
`00010010` 中有两个 1,补上校验位 1 后整体有奇数个 1,异或结果为 1,因此 C 正确。
下列关于 NOI 系列活动的有关说法,错误的是( )。
正确答案A
NOI 对可用语言、编译器和版本有明确限制,因此“对 C++ 语言的使用没有限制”是错误说法,选择 A。
考虑右图所示的无向图,度最大的结点为( )号结点。

正确答案D
逐条统计与各结点相连的边,结点 6 连接结点 1、2、4、5,度为 4,是图中最大值。
1 | #include <bits/stdc++.h>
2 | using namespace std;
3 | int x, y;
4 | unsigned int n;
5 | int main() {
6 | cin >> n >> x >> y;
7 | unsigned int mask = 0xff;
8 | int x8 = x << 3;
9 | int y8 = y << 3;
10 | unsigned int nx = (n >> x8) & mask, ny = (n >> y8) & mask;
11 | n &= (~(mask << x8));
12 | n &= (~(mask << y8));
13 | n |= (nx << y8);
14 | n |= (ny << x8);
15 | cout << "0x";
16 | cout << std::hex << n << endl;
17 | return 0;
18 | }假设输入的 `n` 是 32 位无符号整数范围内的整数,`x,y` 是不超过 3 的自然数,完成下面的判断题和单选题。
代码中 `mask` 变量的值转化为二进制的低 16 位结果是 `0000 0000 1111 1111`。( )
正确答案正确
`0xff` 等于十进制 255,写成低 16 位二进制正是 `0000 0000 1111 1111`,所以判断正确。
当输入 `x=0` 的时候,`nx` 表示 `n` 中最低八位对应的字节的数据。( )
正确答案正确
当 `x=0` 时 `x8=0`,表达式 `(n >> 0) & 0xff` 保留 `n` 的最低 8 位,因此 `nx` 表示最低字节。
去掉程序第 11 行至第 12 行中 `(~(mask << x8))` 和 `(~(mask << y8))` 两处中的最内层括号不会改变程序的结果。( )
正确答案错误
去掉内层括号后会按 `(~mask) << x8` 计算,而原式是 `~(mask << x8)`;两者一般不同,所以会改变结果。
当输入为 `15078 0 1` 时,变量 `nx,ny` 的值分别为多少?( )
(提示:十进制数 15078 与十六进制数 3AE6 相同)
正确答案A
,最低字节为 `0xE6`,次低字节为 `0x3A`,因此 `nx,ny` 分别为 `0xE6,0x3A`。
当输入为 `23270 0 1` 时,输出为( )。
(提示:十进制数 23270 与十六进制数 5AE6 相同)
正确答案D
;程序交换第 0、1 个字节后得到 `0xE65A`,并以十六进制输出。
以下哪一个变量的类型修改可能影响程序的输出?( )
正确答案C
把 `mask` 改为 `int` 后,`0xff << 24` 可能产生有符号整数无法表示的结果,触发未定义行为并影响输出,因此选择 C。
1 | #include <bits/stdc++.h>
2 | using namespace std;
3 |
4 | int n, k;
5 |
6 | int func(vector <int> &nums) {
7 | int ret = 0;
8 | for(int i = n; i > k; i--) {
9 | if(nums[i] > nums[i - k]) {
10 | swap(nums[i], nums[i - k]);
11 | ret++;
12 | }
13 | }
14 | return ret;
15 | }
16 |
17 | int main() {
18 | cin >> n >> k;
19 | vector <int> a(n + 1, 0);
20 | for(int i = 1; i <= n; i++)
21 | cin >> a[i];
22 | int counter = 0, previous = -1;
23 | while(counter != previous){
24 | previous = counter;
25 | counter += func(a);
26 | }
27 | for(int i = 1; i <= n; i++)
28 | cout << a[i] << ",";
29 | cout << endl << counter << endl;
30 | return 0;
31 | }假设输入的 `n,k` 是不超过 100000 的正整数,输入的 是不超过 的整数,`k` 小于等于 `n`,完成下面的判断题和单选题。
当输入的 `k` 为 1,程序将 `a` 从小到大排序。( )
正确答案错误
交换条件是右侧元素大于左侧元素,较大的元素会不断向左移动;`k=1` 时最终得到从大到小而非从小到大的顺序。
在题目限制的输入规模下,`counter` 可能会溢出。( )
正确答案正确
`counter` 最坏可达到约 ;当 时约为 ,超过 32 位 `int` 上限,所以可能溢出。
(1 分)当输入为 `8 1 1 9 2 3 4 6 8 7`,输出共有 18 个可见字符。( )
正确答案正确
程序最终输出 `9,8,7,6,4,3,2,1,` 和两位数的 `counter`;第一行 16 个可见字符、第二行 2 个,共 18 个。
当输入的 `k` 为 1,该程序的排序方法最接近( )。
正确答案A
当 `k=1` 时每轮都比较相邻元素并按需要交换,反复扫描直至无交换,最接近冒泡排序。
该程序的时间复杂度为( )。
正确答案D
数组按下标模 `k` 分成约 `k` 条链,每条长度约 ,对各链做冒泡式排序,总复杂度为 。
当输入为 `8 3 1 5 2 6 3 7 4 8`,输出的第一行第三个数字为( )。
正确答案C
`k=3` 时下标 3、6 属于同一组,较大值 7 会被交换到下标 3;程序稳定后第一行第三个数字为 7。
1 | #include <iostream>
2 | #include <vector>
3 | #include <queue>
4 | using namespace std;
5 | const int MAXN = 200001;
6 | int main() {
7 | int n, m, l, r, w;
8 | cin >> n >> m;
9 | vector <int> dist(MAXN, -1);
10 | vector <bool> vis(MAXN, false);
11 | vector <vector <pair<int, int> > > go(MAXN);
12 | for(int i = 1; i <= m; i++) {
13 | cin >> l >> r >> w;
14 | go[l].push_back(make_pair(r + 1, w));
15 | go[r + 1].push_back(make_pair(l, -w));
16 | }
17 | queue <int> q;
18 | dist[1] = 0, vis[1] = true;
19 | q.push(1);
20 | while(!q.empty()) {
21 | int x = q.front(); q.pop();
22 | for(auto i : go[x]) {
23 | if(!vis[i.first]) {
24 | vis[i.first] = true;
25 | dist[i.first] = dist[x] + i.second;
26 | q.push(i.first);
27 | }
28 | }
29 | }
30 | if(dist[n + 1] == -1) cout << "sorry" << endl;
31 | else cout << dist[n + 1] << endl;
32 | return 0;
33 | }假设输入的 `n,m` 是不超过 200000 的正整数,程序第 13 行每次输入的 `l,r` 保证 `l<=r`,完成下面的判断题和单选题。
交换程序的第 14 行与第 15 行,不影响程序运行的结果。( )
正确答案正确
第 14、15 行分别向两个端点的邻接表加入互为反向的边,交换这两条独立语句的执行先后不改变最终图结构。
输入的 `r` 的最大值为 `n` 时,程序可以正常运行。( )
正确答案错误
当 `n=200000` 且出现 `r=n` 时会访问下标 `r+1=200001`,但长度为 200001 的向量最大合法下标是 200000,因此不能保证正常运行。
在程序的第 17 行至第 29 行,相同的数可能重复进入队列。( )
正确答案错误
结点在入队前就立刻设置 `vis=true`,后续边无法再次把它加入队列,所以同一编号不会重复入队。
当输入的 `l` 最小值为 ,输入的 `r` 的最大值为 ,最多有( )个元素进入过队列。
正确答案D
边的端点形式是 `l` 和 `r+1`。当最小 `l=x`、最大 `r=y` 时,可能涉及从 到 的所有编号,共 个。
当输入的 `n` 为偶数,且 `r=l+1` 时,`m` 至少为( )时输出不为 `sorry`。
正确答案A
当 `r=l+1` 时,每条边连接 `l` 与 `l+2`。`n` 为偶数时,从 1 到 `n+1` 至少需要 条这样的边,且可由连续奇数端点达到。
当输入为 `5 3 1 3 4 3 4 2 4 5 3` 时,输出为( )。
正确答案D
输入建立边 权 4、 权 2、 权 3;从 1 到 6 的可达路径权值为 。
(优美的进制)给出整数 `n`;`k` 进制是优美的,当且仅当 `n` 在 `k` 进制下至少有两位,且每一位的数值都不同。求对于给定的 `n`,有哪些进制是优美的,不存在则输出 -1。试补全程序。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000;
int n;
int vis[MAXN], a[MAXN];
vector<int> ans;
int check(int k) {
int x = n, top = 0;
for (int i = 0; i <= k; i++) vis[i] = 0;
while (①) {
a[++top] = ②;
x = ③;
}
if (top < 2)
return 0;
for (int i = 1; i <= top; i++) {
if (④)
return 0;
vis[a[i]] = 1;
}
return 1;
}
int main() {
cin >> n;
for (int i = ⑤; i <= n; i++) {
if (check(i))
ans.push_back(i);
}
if (ans.empty()) {
cout << -1;
}
for (int i = 0; i < ans.size(); i++)
cout << ans[i] << " ";
return 0;
}① 处应填( )。
x > 0x > 1x / k > 0x / k > 1正确答案A
要提取 `n` 在 `k` 进制下的每一位,应在 `x>0` 时持续处理,因此 ① 填 `x > 0`。
② 处应填( )。
x / kx % k(x - 1) / k + 1(x - 1) % k + 1正确答案B
`x % k` 得到 `x` 的最低一位 `k` 进制数值,应存入数组,所以 ② 选择 B。
③ 处应填( )。
x / kx % k(x - 1) / k + 1(x - 1) % k + 1正确答案A
提取余数后用 `x / k` 去掉当前最低位,以便继续分解,因此 ③ 选择 A。
④ 处应填( )。
vis[i] == 1vis[a[i]] == 0vis[i] == 0vis[a[i]] == 1正确答案D
`vis[a[i]]` 记录数位值 `a[i]` 是否出现过;若它已经等于 1,就存在重复数位,应返回 0。
⑤ 处应填( )。
1n - 120正确答案C
通常的进制至少为 2,且题目要求枚举 `k` 进制,因此循环应从 2 开始,选择 C。
(好运的日期)一个日期可以用 `x` 年 `y` 月 `z` 日来表示。我们称一个日期是好运的,当且仅当 为质数,其中 `w` 为 `x` 年 `y` 月的总天数。输入 `x,y,z`,判断其对应的日期是否好运。保证 `x` 是不超过 2024 的正整数,`y` 是不超过 12 的正整数,`x,y,z` 可以构成一个合法的日期。试补全线性筛法算法,空间限制 512 MiB。
#include <bits/stdc++.h>
using namespace std;
const int MAXW = ①;
const int days[13] = {0, 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int prime[MAXW], cnt;
bool not_prime[MAXW];
void linear_prime(int n) {
--n;
not_prime[0] = not_prime[1] = true;
for(int i = 2; i <= n; i++) {
if(not_prime[i] == false)
prime[++cnt]=i;
for(int j = 1; ②; j++) {
not_prime[i * prime[j]] = 1;
if(i % prime[j] == 0)
③;
}
}
}
bool check(int n) {
return ④;
}
int main() {
linear_prime(MAXW);
int x, y, z, w;
cin >> x >> y >> z;
if(y == ⑤)
w = check(x) ? 29 : 28;
else
w = days[y];
if(not_prime[x * y * (w - z + 1)])
cout << "unlucky" << endl;
else
cout << "lucky" << endl;
return 0;
}① 处可以填( )。
753005100000000007250412024正确答案A
表达式最大值不超过 ,数组长度必须大于最大下标;753005 足够且能在空间限制内,选择 A。
② 处应填( )。
j <= cnti * prime[j] <= n(j <= cnt) && (i * prime[j] <= n)(i <= cnt) && (prime[i] * prime[j] <= n)正确答案B(另接受:C)
标准写法需要保证乘积不超过 `n`;选项 B 借助算法在遇到最小质因子时退出的性质可以成立,选项 C 额外显式限制 `j<=cnt` 也成立。
③ 处应填( )。
not_prime[i] = truereturncontinuebreak正确答案D
当 `prime[j]` 整除 `i` 时应执行 `break`,保证每个合数只由其最小质因子对应的组合筛到。
④ 处应填( )。
n % 4 == 0(n % 400 == 0 || (n % 4 == 0 && n % 100 != 0))(n % 4 == 0 && n % 100 != 0)(n % 100 == 0 || (n % 4 == 0 && n % 100 != 0))正确答案B
公历闰年条件是能被 400 整除,或能被 4 整除但不能被 100 整除,对应选项 B。
⑤ 处应填( )。
1782正确答案D
只有 2 月的天数需要根据闰年在 28 与 29 之间选择,因此 ⑤ 应填 2。