一、单项选择题
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
试卷解析 · 理解每一步
CSPJ-2026-R1-Mock-Luogu
试卷解析总览,可直接查看每题答案与解析。
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
在 64 位计算机中,下列 C++ 基本类型中( )的单个变量占用的内存最大。
正确答案C
在常见 64 位平台上,`double` 通常占 8 字节,`int` 占 4 字节,`bool` 和 `char` 通常各占 1 字节,因此选择 C。
Ubuntu 是常见的 Linux 操作系统。假设当前登录的用户为 `luogu`,当前所在的工作目录为 `/home/luogu`,使用( )命令,可以在 `/home/sjtu/phd` 下新建子目录 `paper`。
mv ./sjtu/phd/papermkdir ~/sjtu/phd/papermv /home/sjtu/phd/papermkdir ../sjtu/phd/paper正确答案D
当前目录是 `/home/luogu`,`..` 表示 `/home`,所以 `mkdir ../sjtu/phd/paper` 会创建 `/home/sjtu/phd/paper`。
阅读下面的代码,其中说法错误的是( )。
#include <bits/stdc++.h>
using namespace std;
stack<int> s1, s2;
int T, x;
int main() {
cin >> T;
while (T--) {
string op;
cin >> op;
if (op == "in") {
cin >> x;
s1.push(x);
} else {
if (s2.empty()) {
while (!s1.empty()) {
s2.push(s1.top());
s1.pop();
}
}
cout << s2.top() << endl;
s2.pop();
}
}
return 0;
}正确答案C
第一次 `out` 输出 1;随后 2、3 转入 `s2` 后依次输出 2、3,因此实际输出是 `1 2 3`,C 的说法错误。
、、 和 中,最大的数的十进制表示为( )。
正确答案A
四个数换算为十进制依次是 28、24、25、27,最大值为 28。
阅读下面的材料,完成本题。
在计算机底层,`int` 类型与 `unsigned int` 类型的加法运算在 ALU(算术逻辑单元)中的执行路径完全一致——ALU 仅对两个操作数进行二进制补码加法,得到相同的 32 位二进制和,并同时设置状态标志位(如进位标志 CF 和溢出标志 OF)。二者的差异仅在于如何解释这个二进制结果:若解释为有符号数(`int`),则按补码规则读取;若解释为无符号数(`unsigned int`),则按普通二进制数值读取,因此同一个二进制和可能对应不同的十进制值。当加法结果超出该类型的表示范围时,即发生溢出,ALU 并不会抛出异常或中断,而是直接截断高位,仅保留低 32 位作为结果,并更新标志位——对于无符号数溢出,ALU 将进位标志 CF 置 1(表示最高位产生进位),而对于有符号数溢出,ALU 将溢出标志 OF 置 1(表示符号位错误),但计算结果本身仍被保存为截断后的低 32 位,后续程序需根据类型和标志位自行判断是否发生了溢出,ALU 本身不对溢出做额外处理。
ALU 是算术逻辑单元,根据材料可以推断其属于( )的一部分。
正确答案A
ALU 负责算术运算和逻辑运算,是 CPU 的核心组成部分之一。
根据第 5 题前的材料,`int` 类型变量 `x` 的值为 -1,将其强制类型转换为 `unsigned int` 类型输出,输出的值为( )。
正确答案C
32 位补码的 -1 全部位都是 1,按 `unsigned int` 解释时为 。
根据第 5 题前的材料,下面代码的输出为( )。
#include <iostream>
int main() {
unsigned int a = 2147483648;
int b = 1234567890;
std::cout << int(a + b) << std::endl;
}正确答案B
`a+b=3382051538`,其 32 位结果按有符号补码解释为 。
下面的表格是图 G 的邻接表,关于图 G 说法错误的是( )。
1 2 3 4 5
2 1 3
3 1 2 6
4 1 5
5 1 4
6 3正确答案C
邻接关系成对出现,图可以是无向图;结点 1 的度为 4 且所有结点都可由 1 连通,因此只有 1 个连通块,C 错误。
下列代码的输出为( )。
#include <iostream>
using namespace std;
int main() {
int A = 1, B = 1;
int& a = A, b = B;
a = 2, b = 2;
std::cout << A << ' ' << B << std::endl;
}正确答案C
声明中只有 `a` 是 `A` 的引用,`b` 是由 `B` 初始化的普通 `int`。赋值后 `A=2`、`B=1`,输出 `2 1`。
给定一个长度为 的数列 ,从中选择若干个元素,并保持它们在原数列中的相对顺序不变,组成一个新序列 。若该新序列满足 ,则称 为原数列的一个上升子序列。在所有可能的上升子序列中,长度 达到最大值的那个,称为该数列的最长上升子序列(LIS)。下列方法中,( )不能正确求解一个序列的最长上升子序列。
正确答案A
从第一个数开始的贪心会漏解,例如序列 `5,1,2,3,4` 被迫先选 5,只得到长度 1,而真实 LIS 长度为 4。
哈夫曼编码是实现信息压缩的常见编码方式。假设有一组字符 ,对应的频率分别为 0.05、0.09、0.12、0.13、0.16、0.45。那么字符串 `abcdef` 共有( )种可能的哈夫曼编码。
正确答案C
6 个叶子构成的哈夫曼树有 5 个内部结点;每个内部结点的左右子树均可交换,故共有 种编码。
二叉树 T 的中序遍历为 `CADBEFG`,后序遍历为 `CBDAFGE`,则其前序遍历为( )。
正确答案A
后序末尾确定根为 E;左子树由中序 `CADB`、后序 `CBDA` 得到前序 `ACDB`,右子树前序为 `GF`,故总前序为 `EACDBGF`。
在 1 到 200 的正整数中,能被 3 或 5 整除,但不能被 7 整除的整数共有( )个。
正确答案B
能被 3 或 5 整除的数有 个;其中还能被 7 整除的有 个,所以答案是 。
数字 1、2、3、4、5、6 排成一列,要求奇数之间的相对顺序保持不变,偶数之间的相对顺序也保持不变,则共有( )种不同的排列。
正确答案B
奇数序列 `1,3,5` 和偶数序列 `2,4,6` 的内部顺序固定,只需从 6 个位置中选 3 个放奇数,共 种。
大语言模型(LLMs)技术发展日新月异。关于 LLM 与 CCF 有关活动,说法不正确的是( )。
正确答案D
CSP-J/S 第一轮是受监管的认证考试,选手不能使用 LLM 辅助完成试题,因此 D 的说法不正确。
1 | #include <iostream>
2 | using namespace std;
3 |
4 | bool isPrime(int n) {
5 | for (int i = 2; i < n; ++i) {
6 | if (n % i == 0) {
7 | return false;
8 | }
9 | }
10 | return true;
11 | }
12 |
13 | int main() {
14 | int n;
15 | cin >> n;
16 | for (int i = 2; i + 2 <= n; ++i) {
17 | if (isPrime(i) && isPrime(i + 2)) {
18 | cout << i << " " << i + 2 << endl;
19 | }
20 | }
21 | return 0;
22 | }假设输入的 `n` 是 5 到 1000 之间的正整数,完成下面的判断题和单选题。
当输入为 14 时,输出的所有整数之和为 44。( )
正确答案正确
输入 14 时输出 `(3,5)`、`(5,7)`、`(11,13)`,所有整数之和为 。
将第 16 行的 `int i = 2` 修改为 `int i = 1`,程序输出不变。( )
正确答案错误
原函数会把 1 错判为质数。循环从 1 开始后会额外输出 `(1,3)`,所以程序输出发生变化。
无论输入为多少,输出的所有整数均为奇数。( )
正确答案正确
2 是唯一偶质数,但 `(2,4)` 不是孪生质数对;程序实际输出的孪生质数都大于 2,因此均为奇数。
当输入为 50 时,输出的所有整数之和为( )。
正确答案B
不超过 50 的输出数对为 `(3,5)`、`(5,7)`、`(11,13)`、`(17,19)`、`(29,31)`、`(41,43)`,总和为 224。
将第 5 行的 `i < n` 修改为以下哪个时,程序输出不变?( )
i <= ni * i < ni * i <= ni * i * i < n正确答案C
判断合数只需试除到平方根,并且完全平方数的平方根必须被检查,所以条件应为 `i * i <= n`。
1 | #include <iostream>
2 | #include <string>
3 | #include <vector>
4 | #include <algorithm>
5 | using namespace std;
6 | int main() {
7 | string a, b;
8 | cin >> a >> b;
9 | int n = a.size(), m = b.size();
10 | vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
11 | for (int i = 0; i <= n; ++i) {
12 | for (int j = 0; j <= m; ++j) {
13 | if (i == 0) {
14 | dp[i][j] = j;
15 | }
16 | else if (j == 0) {
17 | dp[i][j] = i;
18 | }
19 | else if (a[i - 1] == b[j - 1]) {
20 | dp[i][j] = dp[i - 1][j - 1] + 1;
21 | }
22 | else {
23 | dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1;
24 | }
25 | }
26 | }
27 | cout << dp[n][m] << endl;
28 | return 0;
29 | }假设输入的 `a`、`b` 是长度不超过 1000 的仅包含小写字母的字符串,完成下面的判断题和单选题。
若交换输入的 `a` 和 `b`,程序的输出一定不变。( )
正确答案正确
该 DP 计算两个字符串的最短公共超序列长度,交换两个字符串不会改变这一长度,因此输出不变。
若对调代码第 10 行的 `n`、`m`,可能会造成程序运行时错误。( )
正确答案正确
若只在第 10 行交换 `n`、`m`,数组维度与后续 `i<=n`、`j<=m` 的循环不再对应;当两长度不等时可能越界。
程序的输出一定大于 。( )
正确答案错误
当 `a` 与 `b` 完全相同且长度相等时,输出就是该长度,等于 ,并非一定严格大于。
当输入为 `aba bab` 时,程序的输出为( )。
正确答案A
`aba` 与 `bab` 的最长公共子序列长度为 2,因此最短公共超序列长度为 。
当输入为 `abcddd acbded` 时,程序的输出为( )。
正确答案B
两个长度均为 6 的字符串有长度 4 的最长公共子序列,例如 `abdd`,所以输出为 。
假设输入的 `a`、`b` 都是长度为 2 且仅包含 `abcd` 四种字母的字符串。有多少种不同的有序字符串对 `a`、`b` 使得程序的输出为 3?( )
正确答案D
共有 个有序字符串对。输出 2 的相同串有 16 对,完全没有公共字符的有 对,其余 对输出 3。
1 | #include <iostream>
2 | #include <string>
3 | #include <algorithm>
4 | using namespace std;
5 | int n;
6 | string s;
7 | int dfs(string t, int lst) {
8 | int ret = 0;
9 | for (int i = 0; i <= n; i++)
10 | if (t[i] != '1')
11 | ret = 1e9;
12 | if (ret == 0) return 0;
13 | for (int i = 0; i <= n; i++)
14 | if (i != lst && s.substr(n - i, i) == t.substr(0, i)) {
15 | string cur = t;
16 | cur[i] ^= 1;
17 | ret = min(ret, dfs(cur, i) + 1);
18 | }
19 | return ret;
20 | }
21 | int main() {
22 | cin >> s;
23 | n = s.size();
24 | string t0(n + 1, '0');
25 | cout << dfs(t0, -1);
26 | return 0;
27 | }假设若无特殊说明,输入的字符串 `s` 是一个长度不超过 18 的非空 01 串,完成下面的判断题和单选题。字符 `0` 和 `a` 的 ASCII 码分别是 48 和 97。
将第 11 行的 `1e9` 换成 `1234567`,程序的输出结果不变。( )
正确答案正确
长度至多 18 时,程序涉及的 `t` 状态数量不超过 ,有效返回值远小于 1234567;替换哨兵值不会改变最小值。
将第 14 行的 `if` 语句中,`i != lst &&` 去掉,程序的输出结果不变。( )
正确答案错误
第 `i` 次操作只翻转 `t[i]`,不会改变长度为 `i` 的前缀条件;去掉 `i != lst` 后可立即再次选择同一 `i` 翻转回来,形成递归循环。
下列说法中正确的是( )。
正确答案D(另接受:B)
两组指定输入的输出都为 168;按题面“自然溢出”的字面含义,递归结果不会产生 `int` 溢出;且 `'a'-'0'='1'`、`'a'-'1'='0'`,与 `^=1` 的翻转效果相同,所以主答案为 D。若原文实际想表达“栈溢出”,则 B 也可成立,系统兼容该答案。
假设输入为 `00000001`,那么程序的输出为( )。
正确答案A
把 `t` 视为 9 位状态,按第 14 行的合法转移逐层计算,初始状态到全 1 状态的返回值为 341。
假设输入为 `110111011110111110`,那么函数 `dfs` 将被调用( )次。
正确答案B
对给定的 18 位输入精确展开递归树,连同初始调用共调用 `dfs` 524288 次,即 次。
假设输入为 `001000100001000001`,那么程序的输出为( )。
正确答案D
对给定输入按合法状态转移计算,程序返回 289745;它不等于 21、289746 或 525739,因此选择“ABC 均错”。
(序列第 小)给出一个长度为 的数列 和一个正整数 ,你需要输出第 小的数字。输入保证 ,,且 均为整数。下面的程序采用二分答案的方法,通过二分法找到最小的 ,使得至少 个数字不超过 。试补全程序。
#include <iostream>
using namespace std;
int n, k, a[100'005];
bool check(int x) {
int c = 0;
for (int i = 1; i <= n; i++)
if (/* ① */)
c++;
return /* ② */;
}
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
int l = 1, r = /* ③ */;
while (l < r) {
int x = /* ④ */;
if (check(x))
r = x;
else
/* ⑤ */;
}
cout << l << endl;
return 0;
}① 处应填( )。
a[i] <= xa[i] < xx <= a[i]x < a[i]正确答案A
`check(x)` 要统计不超过 `x` 的元素个数,所以条件应为 `a[i] <= x`。
② 处应填( )。
c <= kc < kk <= ck < c正确答案C
当至少有 `k` 个元素不超过 `x` 时,`x` 才是可行上界,因此返回条件是 `k <= c`。
③ 处应填( )。
na[n]1 << 322e9正确答案D
所有 ,因此 `r=2e9` 一定覆盖答案;`a[n]` 未经排序,不能保证是上界。
④ 处应填( )。
(l + r) / 2(l + r + 1) >> 1l + (r - l) >> 1l + (r - l) / 2正确答案D
需要向下取整的中点,`l + (r - l) / 2` 与目标一致且避免 `l+r` 超出 32 位 `int`,所以选 D。
⑤ 处应填( )。
l = x + 1l = xbreakl += x正确答案A
当 `check(x)` 为假时答案严格大于 `x`,应令 `l=x+1`,从搜索区间中排除 `x`。
(走迷宫)有一个 的网格迷宫。记第 行第 列的格子为 。迷宫由空地(用 `.` 表示)和墙壁(用 `#` 表示)组成。起点是 ,终点是 ,保证起点和终点都是空地。小 R 希望使用两种操作从起点到达终点:
- 步行:移动到上下左右相邻的空地。 - 传送:移动到上下左右距离为 2 的空地。中间跨越的格子可以是空地也可以是墙壁。
小 R 最多使用 次传送。请计算她到达终点的最少操作次数。如果无法到达,输出 -1。输入保证 ,。输入的 `grid[i][j]` 只有 `.` 和 `#` 两种字符。下面的程序使用广度优先搜索完成本题。试补全程序。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105, MAXK = 15;
const int dx[4] = /* ① */;
const int dy[4] = {0, 0, -1, 1};
int n, m, k, dis[MAXN][MAXN][MAXK];
char grid[MAXN][MAXN];
struct Node {
int x, y, k;
};
int bfs() {
memset(dis, 0x3f, sizeof(dis));
queue<Node> q;
q.push({1, 1, 0});
dis[1][1][0] = 0;
while (/* ② */) {
Node u = q.front();
q.pop();
if (u.x == n && u.y == m) {
return /* ③ */;
}
for (int i = 0; i < 4; i++) {
int nx = u.x + dx[i];
int ny = u.y + dy[i];
if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && grid[nx][ny] != '#') {
if (dis[nx][ny][u.k] > dis[u.x][u.y][u.k] + 1) {
dis[nx][ny][u.k] = dis[u.x][u.y][u.k] + 1;
q.push({nx, ny, u.k});
}
}
}
if (/* ④ */) {
for (int i = 0; i < 4; i++) {
int nx = u.x + dx[i] * 2;
int ny = u.y + dy[i] * 2;
int nk = u.k + 1;
if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && grid[nx][ny] != '#') {
if (dis[nx][ny][nk] > dis[u.x][u.y][u.k] + 1) {
dis[nx][ny][nk] = dis[u.x][u.y][u.k] + 1;
/* ⑤ */;
}
}
}
}
}
return -1;
}
int main() {
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> grid[i][j];
}
}
cout << bfs() << endl;
return 0;
}① 处应填( )。
{0, 0, -1, 1}{0, -1, 1, 0}{-1, 1, 0, 0}{-1, 1, -1, 1}正确答案C
`dy={0,0,-1,1}` 已表示左右方向,对应的 `dx` 应为 `{-1,1,0,0}`,共同覆盖上下左右。
② 处应填( )。
!q.empty()!q.size()!q.clear()q.front()正确答案A
BFS 应在队列非空时继续处理结点,因此循环条件是 `!q.empty()`。
③ 处应填( )。
dis[u.x][u.y][u.k] + 1dis[u.x][u.y][u.k]dis[u.x][u.y][k]dis[u.x][u.y][0]正确答案B
结点第一次从 BFS 队列取出时,其 `dis[u.x][u.y][u.k]` 已是对应状态的最短操作次数,到达终点应直接返回该值。
④ 处应填( )。
u.k == ku.k > 0u.k <= ku.k < k正确答案D
只有已经使用的传送次数 `u.k` 小于上限 `k` 时,才能继续使用一次传送,因此条件是 `u.k < k`。
⑤ 处应填( )。
q.push(nx, ny, nk)q.push_back({nx, ny, nk})q.insert({nx, ny, nk})q.push({nx, ny, nk})正确答案D
队列元素类型是 `Node`,应使用 `q.push({nx, ny, nk})` 把新的状态入队。