一、单项选择题
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
CSPJ-2025-R1-Mock-Luogu
试卷解析总览,可直接查看每题答案与解析。
(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
GNU GCC 是常用的 C/C++ 语言编译器。现需要使用 `g++` 将 `luogu.cpp` 编译为可执行文件 `luogu`,可以使用编译命令( )。
g++ -S luogu luogu.cppg++ -S luogu.cpp luogug++ -o luogu luogu.cppg++ -o luogu.cpp luogu正确答案C
【答案】C
【考点】GCC 编译命令
【解析】 `-o luogu` 指定输出文件名为 `luogu`,最后的 `luogu.cpp` 是待编译源文件,因此命令应为 `g++ -o luogu luogu.cpp`。
【易错点】 `-S` 只生成汇编代码,不能直接得到题目要求的可执行文件。
关于编译语言与解释语言,以下说法错误的是( )。
正确答案B
【答案】B
【考点】编译语言与解释语言
【解析】 编译后的可执行文件可以反复运行;只有源代码改变或构建条件变化时才需要重新编译,所以 B 错误。
【易错点】 不要把“运行前需要编译”误解为“每次运行都要重新编译”。
阅读下面的代码,若输入的 `x` 是 1 至 10 范围内的正整数,输出不可能是( )。
#include <iostream>
using namespace std;
int main() {
int x;
cin >> x;
switch (x) {
case 1: { cout << "A"; break; }
case 3: { cout << "C"; }
default: { cout << "Q"; }
case 5: { cout << "E"; }
}
return 0;
}正确答案D
【答案】D
【考点】switch 贯穿执行
【解析】 输入 1 输出 `A`;输入 3 从 `case 3` 贯穿得到 `CQE`;其他未匹配值从 `default` 贯穿得到 `QE`,输入 5 则输出 `E`。单独的 `Q` 不会出现。
【易错点】 `default` 后没有 `break`,还会继续执行后面的 `case 5`。
()进制数 与十进制数( )相等。
正确答案C
【答案】C
【考点】进制展开
【解析】 进制的 按位权展开为 。
【易错点】 最高位的位权是 ,不是 。
阅读以下代码片段。当代码片段执行完毕后,`ans` 的值为( )。
int N = 10, ans = 0, x = 0;
for (int i = 1; i <= N; i++) {
for (int j = i + 1; j <= N; j++) {
ans += ++x;
}
}正确答案D
【答案】D
【考点】循环计数与等差数列
【解析】 内层循环共执行 次,`x` 依次取 1 到 45,故 `ans=1+2+\cdots+45=1035`。
【易错点】 `ans` 累加的是递增后的 `x`,不是只统计循环次数。
给定一个空栈,支持入栈和出栈操作。将 1 至 10 依次入栈,第一个出栈的数为 8,则第二个出栈的数不可能为( )。
正确答案A
【答案】A
【考点】栈的出栈序列
【解析】 首次弹出 8 后,栈顶是 7;此后可以直接弹出 7,也可以先压入并弹出 9 或 10,但不可能越过 7 到 2 而让 1 第二个出栈。
【易错点】 栈遵循后进先出,尚未弹出的 2~7 会挡在 1 上方。
有序表中有 100 个元素,使用二分法查找元素 X。有( )个数可以通过恰好 5 次查找找到。
正确答案D
【答案】D
【考点】二分查找
【解析】 二分查找的比较过程形成二叉判定树,第 5 层有 个位置,因此恰好比较 5 次找到的元素有 16 个。
【易错点】 题目问的是恰好 5 次,不是最多 5 次。
下面的表格是无向图 G 的邻接矩阵,图 G 中度最大的点的度为( )。
A B C D E
A 0 1 1 0 1
B 1 0 1 0 0
C 1 1 0 1 1
D 0 0 1 0 1
E 1 0 1 1 0正确答案D
【答案】D
【考点】邻接矩阵与顶点度
【解析】 无向图中顶点的度等于邻接矩阵对应行中 1 的个数;C 行有 4 个 1,为最大值。
【易错点】 不要把矩阵总边数或列数当作单个顶点的度。
8 支队伍均分为第一组与第二组进行小组赛。A 队和 B 队在同一组,而与 C 队不在同一组的分组方案数有( )种。
正确答案B
【答案】B
【考点】组合计数
【解析】 第一、第二组有标签。A、B 可同在任一组,再从除 C 外的 5 支队伍中选 2 支同组,方案数为 。
【易错点】 若把两个小组当成无标签集合,会少乘一个 2。
将一根长度为 3 的木棍折为三段,当断点的位置在木棍中等概率分布时,三段木棍可以构成三角形的概率为( )。
正确答案C
【答案】C
【考点】几何概率
【解析】 两个断点把长度归一化后,三段能成三角形等价于最长一段小于 ;在两个断点的单位正方形样本空间中,满足条件区域面积占 。
【易错点】 仅满足三段长度和固定还不够,必须检查最长边小于其余两边之和。
下列关于快速排序的说法中,不正确的是( )。
正确答案B
【答案】B
【考点】快速排序复杂度
【解析】 快速排序在划分极不均衡时会退化为 ,最坏时间复杂度是 ,因此 B 不正确。
【易错点】 平均 不能替代最坏复杂度。
关于整数的各种 8 位二进制编码方法,说法错误的是( )。
正确答案D
【答案】D
【考点】原码、反码与补码
【解析】 -17 的原码是 `10010001`,22 的补码是 `00010110`,-13 的反码是 `11110010`,A、B、C 均正确,所以“以上说法存在错误”本身错误。
【易错点】 负数原码、反码和补码的转换规则不同。
表达式 中, 的系数为( )。
正确答案C
【答案】C
【考点】二项式展开
【解析】 取两次 时幂次为 ,其系数为 。
【易错点】 先用幂次条件确定选取次数,再计算组合系数和符号。
二叉树 T 的中序遍历为 `CGEADBF`,后序遍历为 `GECDFBA`,则其前序遍历为( )。
正确答案A
【答案】A
【考点】二叉树遍历还原
【解析】 后序末尾确定根为 A;由中序划分可还原左子树前序为 `CEG`、右子树前序为 `BDF`,所以整树前序为 `ACEGBDF`。
【易错点】 每次都应先用后序序列末尾找根,再按中序序列分割左右子树。
2024 年,来自谷歌 DeepMind 的米斯·哈萨比斯和约翰·江珀获得了( ),以表彰他们在人工智能方面的贡献。
正确答案C
【答案】C
【考点】科技奖项
【解析】 米斯·哈萨比斯和约翰·江珀获得了 2024 年诺贝尔化学奖,因此选择“诺贝尔奖”。
【易错点】 图灵奖是计算机科学奖项,但题目所述 2024 年奖项是诺贝尔奖。
#include <bits/stdc++.h>
using namespace std;
int main() {
int l, r;
cin >> l >> r;
int cnt = 0;
long long sum = 0;
for (int i = l; i <= r; ++i) {
if ((i & (i - 1)) != 0) {
cnt += 1;
sum += i;
}
}
cout << cnt << " " << sum << endl;
return 0;
}假设输入的 `l` 和 `r` 均为不超过 的正整数,且满足 ,完成下面的判断题和单选题。
当输入为 `2 5` 时,程序的输出为 `2 8`。( )
正确答案正确
【答案】正确
【考点】位运算判定 2 的幂
【解析】 条件 `(i & (i - 1)) != 0` 选中非 2 的幂。区间 2~5 中只有 3、5 被计入,数量为 2、和为 8。
【易错点】 2 和 4 是 2 的幂,不会进入 `if`。
程序的输出总是两个正整数。( )
正确答案错误
【答案】错误
【考点】边界输出
【解析】 若区间只包含一个 2 的幂,例如输入 `1 1`,没有元素被计入,程序输出 `0 0`,并非两个正整数。
【易错点】 0 是非负整数,但不是正整数。
将第 8 行的 `long long` 改为 `int`,程序行为不变。( )
正确答案错误
【答案】错误
【考点】整数溢出
【解析】 当区间较大时,被累加元素的和可接近 ,超过 32 位 `int` 上限;改成 `int` 会发生溢出,程序行为会改变。
【易错点】 `i` 不超过 不代表许多个 `i` 的总和也能放进 `int`。
当输入为 `1 100` 时,程序的输出为( )。
正确答案A
【答案】A
【考点】区间统计
【解析】 1~100 共 100 个数,其中 2 的幂有 1、2、4、8、16、32、64 共 7 个;故 `cnt=93`,`sum=5050-127=4923`。
【易错点】 1 也满足 2 的幂判定,应从计数和总和中排除。
当输入为 `10000 1000000` 时,程序的第一个输出为( )。
正确答案C
【答案】C
【考点】2 的幂计数
【解析】 区间共有 个数,其中 2 的幂为 到 共 6 个,因此首个输出为 。
【易错点】 区间端点都包含在循环范围内。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<int> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
vector<int> dp(m + 1);
dp[0] = 0;
for (int i = 1; i <= m; ++i) {
int now = 0;
for (int j = 0; j < n; ++j) {
if (i >= a[j] && dp[i - a[j]] == 0) {
now = a[j];
}
}
dp[i] = now;
}
cout << dp[m] << endl;
return 0;
}假设输入的 `n` 和 `m` 均为不超过 1000 的正整数,输入的 `a[i]` 均为不超过 `m` 的正整数,完成下面的判断题和单选题。
当输入为 `3 5 1 3 4` 时,程序的输出为 0。( )
正确答案错误
【答案】错误
【考点】动态规划状态模拟
【解析】 依次计算得到 `dp[0..5] = 0,1,0,3,4,3`,所以最终输出 `dp[5]=3`,不是 0。
【易错点】 `now` 会被后面满足条件的 `a[j]` 覆盖。
当输入的数组 `a` 为 `{1}` 且 `m` 为偶数时,程序的输出为 0。( )
正确答案正确
【答案】正确
【考点】奇偶状态
【解析】 当 `a={1}` 时,`dp[i]` 只依赖 `dp[i-1]`:奇数位置为 1,偶数位置为 0,因此偶数 `m` 输出 0。
【易错点】 `dp[0]=0` 使状态从 0 和 1 交替开始。
将第 16 行的条件 `i >= a[j] && dp[i - a[j]] == 0` 改为 `dp[i - a[j]] == 0`,程序可能会产生编译错误。( )
正确答案错误
【答案】错误
【考点】数组越界与编译
【解析】 删除 `i >= a[j]` 后,`i<a[j]` 时会访问负下标;代码仍可通过编译,但运行时发生越界和未定义行为,因此不是编译错误。
【易错点】 能否编译与运行时下标是否合法是两件事。
当输入为 `4 13 1 2 3 4` 时,程序的输出为( )。
正确答案D
【答案】D
【考点】取石子状态
【解析】 可选步长为 1~4 时,输态是 5 的倍数;,最后一个能从输态 10 转移来的步长为 3,所以输出 3。
【易错点】 程序输出的是最后记录的可行步长,不是胜负布尔值。
当输入为 `7 1000 1 2 3 4 5 6 7` 时,程序的输出为( )。
正确答案A
【答案】A
【考点】周期状态
【解析】 步长为 1~7 时,输态是 8 的倍数。1000 能被 8 整除,因此 `dp[1000]=0`。
【易错点】 连续可选 1~7 时状态周期为 8。
当输入的数组 `a` 为 `{1,2,3,4,5}` 时,有( )个符合数据范围的整数 `m` 使得输出为 3。
正确答案B
【答案】B
【考点】周期计数与数据范围
【解析】 步长为 1~5 时,输出 3 恰在 。又因数组元素 5 必须不超过 `m`,需排除 ;从 9 到 999 共 个。
【易错点】 不能忽略题设中的 `a[i] <= m`,否则会多算 `m=3`。
#include <bits/stdc++.h>
using namespace std;
vector<int> primes;
int comp_by[2000005];
void sieve(int n) {
for (int x = 2; x <= n; x++) {
if (comp_by[x] == 0)
primes.push_back(x);
for (int i = 0; i < primes.size(); i++) {
if (x * primes[i] > n) break;
comp_by[x * primes[i]] = primes[i];
if (x % primes[i] == 0) break;
}
}
}
int main() {
freopen("input.txt", "w", stdout);
freopen("output.txt", "r", stdin);
int n;
cin >> n;
sieve(n);
for (int i = 1; i <= n; i++)
cout << comp_by[i] << ' ';
return 0;
}假设输入的 `n` 是不超过 的正整数,完成下面的判断题和选择题。
提示:伯特兰-切比雪夫定理:对任意 ,存在质数 使得 。
程序将从 `input.txt` 读入数据,输出到 `output.txt`。( )
正确答案错误
【答案】错误
【考点】freopen 重定向
【解析】 第一条把标准输出以写模式重定向到 `input.txt`,第二条把标准输入以读模式重定向到 `output.txt`,方向与题目描述正好相反。
【易错点】 `freopen` 的第三个参数决定重定向的是 `stdin` 还是 `stdout`。
交换程序的第 12 行和第 13 行,不会导致数组越界。( )
正确答案正确
【答案】正确
【考点】数组边界
【解析】 交换后会先写 `comp_by[x*primes[i]]` 再判断是否大于 `n`;首次越过 `n` 时乘数至多为 2,故下标不超过 ,仍小于数组长度 2000005。
【易错点】 越过筛选上界 `n` 不等于越过实际数组容量。
对于所有正整数 `i`,满足 ,输出的第 `i` 个数是 0 当且仅当 `i` 是质数。( )
正确答案错误
【答案】错误
【考点】质数筛与特殊值 1
【解析】 筛法中质数位置保持 0,但 `comp_by[1]` 也为 0,而 1 不是质数,所以“当且仅当”不成立。
【易错点】 检验全称命题时不能漏掉范围内的特殊值 1。
该程序的主要流程最接近( )。
正确答案D
【答案】D
【考点】欧拉筛
【解析】 程序按质数表枚举并在遇到 `x` 的最小质因子时停止,使每个合数按其最小质因子生成一次,属于欧拉筛。
【易错点】 埃拉托斯特尼筛通常从每个质数的倍数出发统一标记。
将程序的第 14 行移动到第 11 行,当输入为 1000000 时,输出的第( )个数会发生改变。
正确答案B
【答案】B
【考点】欧拉筛语句顺序
【解析】 把整除判断移到赋值之前后,`x=15` 遇到质数 3 会先退出,45 不再被标记,故第 45 个输出改变;75、105 仍可由更早的乘积标记,97 本来就是质数。
【易错点】 原顺序必须先标记 `x*p`,再在 `p` 整除 `x` 时退出。
当输入为 100 时,输出的所有数字之和为( )。
正确答案C
【答案】C
【考点】最小质因子求和
【解析】 `comp_by` 保存合数的最小质因子。100 以内贡献分别为:偶合数 ,最小质因子为 3、5、7 的奇合数贡献 48、30、21,总和为 197。
【易错点】 质数和 1 的数组值都是 0,不应把它们本身加入总和。
(全排列检查)给定长度为 `n` 的数组 `a`,判断其是否构成全排列。如果 都恰好在数组 `a` 中出现且仅出现一次,那么就称这个数组是一个全排列。
试补全程序。
#include <bits/stdc++.h>
using namespace std;
bool is_permutation(vector<int> &a) {
int n = /* ① */;
vector<int> count(/* ② */);
for (int i = 0; i < n; i++) {
if (/* ③ */)
count[a[i]]++;
else
/* ④ */;
}
for (int i = 1; i <= n; i++)
if (count[/* ⑤ */] > 1)
return false;
return true;
}
int main() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++)
cin >> a[i];
if (is_permutation(a))
cout << "The sequence is a permutation.";
else
cout << "The sequence is not a permutation.";
return 0;
}① 处应填( )。
a.length()a.size()a.back()a.capacity()正确答案B
【答案】B
【考点】vector 长度
【解析】 形参 `a` 是 `vector<int>`,元素个数由 `a.size()` 返回,因此 ① 填 `a.size()`。
【易错点】 `capacity()` 是已分配容量,不一定等于实际元素个数。
② 处应填( )。
0nn + 11000000000正确答案C
【答案】C
【考点】计数数组下标
【解析】 程序会访问 `count[1]` 到 `count[n]`,所以需要 `n+1` 个元素,合法下标为 0~n。
【易错点】 若只开 n 个元素,访问 `count[n]` 会越界。
③ 处应填( )。
1 <= a[i] && a[i] <= n1 <= a[i] <= n1 <= a[i] || a[i] <= na[i] < 1 || a[i] > n正确答案A
【答案】A
【考点】C++ 范围判断
【解析】 合法值必须同时满足 `1 <= a[i]` 和 `a[i] <= n`,应使用逻辑与连接两个比较。
【易错点】 C++ 不支持数学式的链式比较,`1 <= a[i] <= n` 会被分两次求值。
④ 处应填( )。
breakcontinuereturn truereturn false正确答案D
【答案】D
【考点】异常输入处理
【解析】 一旦发现元素不在 1~n 范围内,数组不可能是全排列,应立即 `return false`。
【易错点】 `break` 或 `continue` 都可能让非法数组进入后续检查并被误判。
⑤ 处应填( )。
ia[i]i - 1i / 2正确答案A
【答案】A
【考点】频次检查
【解析】 循环变量 `i` 正在枚举数值 1~n,应检查对应的 `count[i]` 是否大于 1,所以 ⑤ 填 `i`。
【易错点】 此处的 `i` 是数值下标,不是原数组的位置。
(跳跃)给定一个数组 ,每次跳跃从当前位置 `x` 跳至位置 `a[x]`。回答 `q` 次询问,每次给出 `(x,k)`,输出从 `x` 跳跃 `k` 次后的位置编号。
试补全程序。
#include <iostream>
using namespace std;
const int N = 100010, LOG = 20;
int a[N], dp[N][LOG];
int main() {
int n, q;
cin >> n >> q;
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n; i++) {
dp[i][0] = /* ① */;
}
for (int k = 1; k < LOG; k++) {
for (int i = 0; i < n; i++) {
dp[i][k] = /* ② */;
}
}
while (q--) {
int x, k;
cin >> x >> k;
int u = x;
for (int j = 0; j < LOG; j++) {
if (/* ③ */) {
u = /* ④ */;
}
}
cout << /* ⑤ */ << endl;
}
return 0;
}① 处应填( )。
ia[i]0dp[i][1]正确答案B
【答案】B
【考点】倍增初始化
【解析】 `dp[i][0]` 表示从位置 `i` 跳 次后的编号,按定义就是 `a[i]`。
【易错点】 `dp[i][0]` 不是原地不动状态。
② 处应填( )。
dp[dp[i][k - 1]][k - 1]dp[i][k - 1] + dp[i][k - 1]dp[i - 1][k - 1]dp[k - 1][i]正确答案A
【答案】A
【考点】倍增转移
【解析】 跳 次可拆成两段 次,先到 `dp[i][k-1]`,再跳同样次数,因此转移为 `dp[dp[i][k-1]][k-1]`。
【易错点】 两段跳跃要做函数复合,不能把位置编号相加。
③ 处应填( )。
k & jk >> j(k >> j) & 1(k >> j) ^ 1正确答案C
【答案】C
【考点】二进制拆分
【解析】 枚举第 `j` 位时,只有 `k` 的该位为 1 才执行对应的 次跳跃,条件应为 `(k >> j) & 1`。
【易错点】 `k >> j` 可能大于 1,显式取最低位才能得到当前比特。
④ 处应填( )。
dp[j][u]dp[k][u]dp[u][j]a[u]正确答案C
【答案】C
【考点】倍增查询
【解析】 当第 `j` 位有效时,当前位置 `u` 应沿预处理表跳 次,更新为 `dp[u][j]`。
【易错点】 倍增表第一维是当前位置,第二维是二进制位。
⑤ 处应填( )。
uxkdp[u][0]正确答案A
【答案】A
【考点】查询结果
【解析】 循环结束后 `u` 已经累计完成 `k` 次跳跃,应该直接输出 `u`。
【易错点】 再输出 `dp[u][0]` 会额外多跳一次。