试卷解析 · 理解每一步
普及组 CSP-J 2026 初赛模拟卷 10
CSPJ-2026-R1-Mock-10
试卷解析总览,可直接查看每题答案与解析。
第 1 题(单选题,2 分)
在 Linux 终端中,当前目录已有通过 `g++ main.cpp -o main` 生成的可执行文件 `main`。运行它通常使用命令( )。
正确答案B
解析详情
当前目录通常不在命令搜索路径中,因此运行其中的可执行文件要写成 `./main`。
第 2 题(单选题,2 分)
执行下面的程序片段后,`sum` 的值为( )。
vector<int> a(5, 2);
int sum = 0;
for (int x : a) sum += x;正确答案C
解析详情
`vector<int> a(5,2)` 创建 5 个元素且每个值为 2,累加结果为 。
第 3 题(单选题,2 分)
正整数 和 的最大公约数 定义为能同时整除 和 的最大正整数。那么 ( )。
正确答案A
解析详情
连续取余:,,,,最终余数为 0,因此最大公约数是 3。
第 4 题(单选题,2 分)
1 至 100 的整数的乘积末尾有( )个连续的 0。
正确答案C
解析详情
中因子 2 远多于因子 5,末尾零的个数等于因子 5 的总数:。
第 5 题(单选题,2 分)
执行下面的代码后,字符串 `s` 的值为( )。
string s = "csp";
s.push_back('j');正确答案D
解析详情
`push_back('j')` 在字符串末尾追加一个字符,因此 `s` 变为 `cspj`。
第 6 题(单选题,2 分)
执行下面代码后,输出结果是( )。
string s = "algorithm";
cout << s.find("go");正确答案B
解析详情
字符串下标从 0 开始,子串 `go` 的首字符 `g` 位于下标 2,因此 `find` 返回 2。
第 7 题(单选题,2 分)
5 个有标号的点在没有重边或者自环的情况下,可组成的不同无向图个数为( )。
正确答案B
解析详情
5 个有标号顶点之间共有 对可能的边,每条边都可独立选择存在或不存在,因此图的总数为 。
第 8 题(单选题,2 分)
下面代码的时间复杂度是( )。
for (int i = 1; i <= n; ++i)
for (int j = n; j > 0; j /= 2)
++cnt;正确答案C
解析详情
外层执行 次,内层每次将 `j` 除以 2,执行 次,总复杂度为 。
第 9 题(单选题,2 分)
8 位二进制补码中,`10101011` 表示的数是十进制下的( )。
正确答案C
解析详情
最高位为 1,表示负数。按无符号数计算 `10101011` 为 ,8 位补码对应的有符号值为 。
第 10 题(单选题,2 分)
下列排序算法的常见实现中,稳定的是( )。
正确答案B
解析详情
计数排序在按原顺序写入或使用前缀位置的常见实现中可以保持相等元素的相对顺序;其余三种常见实现不稳定。
第 11 题(单选题,2 分)
已知 `int a = 3, b = 5;`,表达式 `(a | b) ^ (a & b)` 的值为( )。
正确答案B
解析详情
,,所以 `a|b` 为 7、`a&b` 为 1,二者异或得到 6。
第 12 题(单选题,2 分)
已知一个栈的入栈顺序为 (),第 1 个出栈的是 3,那么第 2 个出栈的数有( )种可能。
正确答案B
解析详情
第一个弹出 3 时,栈内仍有 1、2,且栈顶是 2。第二个数可以立即弹出得到 2,也可以先继续入栈到任意 再弹出 ;共有 种。
第 13 题(单选题,2 分)
一个 节点无向图没有重边和自环,它是一棵无根树的必要条件不包括( )。
正确答案D
解析详情
无向树必然连通、无环,并恰有 条边;这些都可作为必要条件。若 ,唯一顶点的度数是 0,仍构成一棵树,因此“每个点度数都大于 0”不是对所有 都成立的必要条件。
第 14 题(单选题,2 分)
用邻接矩阵存储一个有 个顶点的图,其空间复杂度为( )。
正确答案C
解析详情
邻接矩阵需要保存 个位置,因此空间复杂度为 。
第 15 题(单选题,2 分)
将正整数 拆成任意多个正整数之和,使这些加数的乘积最大,则加数中不可能出现( )。
正确答案D
解析详情
若最优拆分中出现加数 5,可把它替换成 2 和 3,和仍为 5,而乘积由 5 增大为 ,与最优性矛盾。因此最优拆分中不可能保留 5。
二、阅读程序(1)
1 | #include <iostream>
2 | using namespace std;
3 | const int N = 1009;
4 | int n, q[N], x[N];
5 | int main() {
6 | cin >> n; // 保证输入的数都是正整数,1 <= x[i] <= n <= 1000
7 | for (int i = 1; i <= n; i++) cin >> x[i];
8 | for (int i = 1; i <= n; i++) {
9 | for (int j = i; j >= x[i] + 1; j--) q[j] = q[j - 1];
10 | q[x[i]] = i;
11 | }
12 | for (int i = 1; i <= n; i++)
13 | cout << q[i] << ' ';
14 | return 0;
15 | }第 16 题(判断题,1 分)
如果输出的每个数都不是 0,那么输入的 `x[i]` 必须互不相同。( )
正确答案错误
解析详情
`x[i]` 可以重复而最终仍无 0,例如本题 Q21 的输入位置序列 `1 1 2 3 1 1 2 3` 含重复值,程序却输出 `6 7 8 5 2 3 4 1`,恰好覆盖 1 到 8。
第 17 题(判断题,1 分)
输出的 个数一定是 的一个排列(取值在 范围内且没有重复)。( )
正确答案错误
解析详情
当 `x[i] > i` 时,第 9 行不会移动已有元素,却会向尚未纳入当前序列的位置写入。比如 时最终 `q` 为 `[0,2]`,既含 0 又缺少 1,不是排列。
第 18 题(判断题,2 分)
输出的 个数中除了 0 以外,其他数都互不相同。( )
正确答案正确
解析详情
第 轮写入的新值就是此前未出现过的编号 ;右移只复制已有非零值并覆盖原位置,不会把一个旧编号分裂成两个保留副本。某些编号可能被覆盖掉,但所有仍非零的编号保持互不相同。
第 19 题(判断题,2 分)
如果输入的 `x[i]` 单调不降,则输出也单调不降。( )
正确答案错误
解析详情
即使 `x[i]` 单调不降,新写入的编号 也可能插到较小编号前面。例如 :前两轮得到 `[2,1]`,第三轮后为 `[2,3,1]`,输出并非单调不降。
第 20 题(单选题,3 分)
固定 ,对各种符合输入限制的 `x[i]` 情况,最好和最坏情况下代码的时间复杂度分别为( )。
正确答案A
解析详情
若每轮都有 `x[i] >= i`,内层循环不执行,总时间为读写和外层循环的 。若始终 `x[i]=1`,第 轮移动 次,总移动数为 。
第 21 题(单选题,3 分)
若输入 `8 1 1 2 3 1 1 2 3`,则输出为( )。
正确答案B
解析详情
依次把编号 插到位置 `x[i]`,前四轮得到 `[2,3,4,1]`;再在位置 1 插入 5、6,得到 `[6,5,2,3,4,1]`;最后把 7 插入位置 2、8 插入位置 3,结果为 `[6,7,8,5,2,3,4,1]`。
二、阅读程序(2)
1 | #include <bits/stdc++.h>
2 | using namespace std;
3 | const int N = 10009;
4 | int n, cur, nxt[N];
5 |
6 | int main() {
7 | cin >> n; // 保证 n 是 1..10000 范围内的整数
8 | for (int i = 1; i <= n; ++i) nxt[i] = i % n + 1;
9 | for (cur = 1; n > 1; --n) {
10 | nxt[cur] = nxt[nxt[cur]];
11 | cur = nxt[cur];
12 | }
13 | cout << cur << endl;
14 | return 0;
15 | }第 22 题(判断题,2 分)
程序运行结束后,除了最后的 `cur`,其他 `nxt` 的值都为 0。( )
正确答案错误
解析详情
初始化后每个 `nxt[i]` 都是 中的后继编号;删除节点时执行 `nxt[cur]=nxt[nxt[cur]]`,写入的仍是另一个正编号。程序从未给 `nxt` 赋 0,因此其他位置不会都变成 0。
第 23 题(判断题,2 分)
若将 `for` 循环内的两句合并为 `cur = nxt[cur] = nxt[nxt[cur]];`,则运行结果不会改变。( )
正确答案正确
解析详情
原代码先把 `nxt[nxt[cur]]` 赋给 `nxt[cur]`,随后再把更新后的 `nxt[cur]` 赋给 `cur`。合并式右侧先求出同一个新后继,再依次赋给 `nxt[cur]` 和 `cur`,状态变化相同。
第 24 题(判断题,2 分)
若将 `for` 循环中的条件 `n > 1` 改为 `n > 0`,则运行结果不会改变。( )
正确答案正确
解析详情
原循环在剩 1 个节点时结束;改为 `n > 0` 后只多执行一次。此时 `nxt[cur]=cur`,故两条语句都仍令其等于 `cur`,随后 `n` 减为 0,最终输出不变。
第 25 题(判断题,2 分)
假如强行输入 `n = -1`,程序会异常退出。( )
正确答案错误
解析详情
输入 `n=-1` 时,初始化循环的条件 `i<=n` 一开始就不成立,主循环条件 `n>1` 也不成立;程序不会访问 `nxt`,而是直接输出初始化后的 `cur=1`,不会因此异常退出。
第 26 题(单选题,3 分)
如上代码的时间复杂度是( )。
正确答案A
解析详情
初始化 `nxt[1..n]` 需要 次操作;主循环每轮让 `n` 减 1,从 执行到 1,共 轮,且每轮为常数操作。因此总时间复杂度为 。
第 27 题(单选题,3 分)
若输入 10000,则输出为( )。
正确答案B
解析详情
程序每次删除当前节点的下一个节点,是步长为 2、从 1 开始的约瑟夫问题。设 ,幸存编号为 ;,故输出 。
二、阅读程序(3)
1 | #include <bits/stdc++.h>
2 | using namespace std;
3 | typedef long long ll;
4 | ll x[10009], s[509][10009], n, m;
5 | int main() {
6 | cin >> n >> m; // 保证 1 <= n <= 10000,1 <= m <= 250000,1 <= x[i] <= 1000000
7 | for (ll i = 1; i <= n; i++) cin >> x[i];
8 | ll D = max(1LL, (ll)sqrt(m));
9 | for (ll d = 1; d <= D; d++)
10 | for (ll i = 1; i <= n; i++)
11 | if (i > d) s[d][i] = s[d][i - d] + x[i];
12 | else s[d][i] = x[i];
13 | for (ll i, d, k; m--;) {
14 | cin >> i >> d >> k; // 保证输入的 1 <= i,d,k <= n
15 | k = min(k, (n - i) / d + 1);
16 | if (d <= D) {
17 | if (i > d) cout << s[d][i + (k - 1) * d] - s[d][i - d] << endl;
18 | else cout << s[d][i + (k - 1) * d] << endl;
19 | } else {
20 | ll sum = 0;
21 | for (int j = 0; j < k; ++j) sum += x[i + j * d];
22 | cout << sum << endl;
23 | }
24 | }
25 | return 0;
26 | }第 28 题(判断题,2 分)
将所有整数类型 `long long` 都换成 `int`,结果不变,因为输入数据都在 `int` 范围内。( )
正确答案错误
解析详情
虽然单个 `x[i]` 和下标都在 `int` 范围内,但一个等差位置序列最多累加 10000 个数,和可达 ,超过 32 位有符号整数上限,改成 `int` 会溢出。
第 29 题(判断题,2 分)
假如 `k` 没有截断(去掉 `k = min(k, (n - i) / d + 1);` 这句),但询问的 `i,d,k` 保证了 ,那么程序结果不会改变。( )
正确答案错误
解析详情
条件只保证末项下标不超过 500,并未保证不超过实际的 `n`。例如取 ,末项下标 248 不超过 500,且 `k <= n`;原程序会把 `k` 截为 26,去掉截断后却读取未预处理的 `s[2][248]`,结果随之改变。
第 30 题(判断题,2 分)
代码占用的内存空间大致为 5MB。( )
正确答案错误
解析详情
数组 `s` 含 个 `long long`,仅它就占约 MB;再加上 `x` 等变量,显然远大于 5 MB。
第 31 题(判断题,2 分)
在不影响时间复杂度的情况下,可以把空间复杂度优化到 。( )
正确答案正确
解析详情
可先存下 个询问并按小步长 `d` 分组,每次只用一个长度为 的数组计算当前 `d` 的前缀和,回答该组后复用空间;大步长询问仍直接枚举。这样时间量级不变,存储输入、询问和答案只需 。
第 32 题(单选题,3 分)
此代码最坏情况下的时间复杂度是( )。
正确答案C
解析详情
令 ,预处理 种步长各扫 个位置,耗时 。当 时,每次查询至多枚举 项, 次合计仍为 ,小步长查询为 。
第 33 题(单选题,3 分)
假如强行将以下某个变量的值输入为负数(其他变量仍为正数),一定会导致数组下标越界的是( )。
正确答案C
解析详情
若 `d` 为负数,必有 `d <= D`,程序进入小步长分支并访问 `s[d][...]`,第一维下标直接为负,必然越界。`i` 或 `k` 为负时,相关算式仍可能因其他正变量而得到合法下标;`n` 为负也可能使循环直接跳过。
三、完善程序(1)整数拆分
输入正整数 ,将其拆分为若干(至少 2 个)连续正整数之和,如 ,求拆分方案数。加数不计顺序,。
1 | #include <bits/stdc++.h>
2 | using namespace std;
3 | int n, ans, sum;
4 | int main() {
5 | cin >> n;
6 | for (int i = 1, j; i <= ①; ++i) {
7 | for (j = i, ②; ③; j++) sum += j;
8 | if (④) ans++;
9 | }
10 | cout << ans << endl;
11 | // 该程序的时间复杂度是 ⑤
12 | return 0;
13 | }第 34 题(单选题,3 分)
① 处应填( )。
nn / 2(n + 1) / 2n / 2 + 1正确答案B
解析详情
拆分至少包含两个连续正整数。若首项 ,则最小的两项和 ,不可能形成方案;枚举到 `n / 2` 已覆盖所有可能首项。
第 35 题(单选题,3 分)
② 处应填( )。
sum = 0sum = isum++sum += j正确答案A
解析详情
每更换一个首项 ,都要重新累计序列 ,因此进入内层循环前必须执行 `sum = 0`。否则 `sum` 会保留上一个首项枚举结束时的值。
第 36 题(单选题,3 分)
③ 处应填( )。
j <= nj < nsum <= nsum < n正确答案D
解析详情
内层循环应在 `sum < n` 时继续把当前 `j` 加入;一旦 `sum` 达到或超过 就停止,再由后续判断是否恰好等于 。因此条件应为 `sum < n`。
第 37 题(单选题,3 分)
④ 处应填( )。
sum >= nsum + j == nsum == nj - i >= 2正确答案C
解析详情
内层循环结束时,`sum` 是以 为首项的连续整数和中第一个不小于 的值。只有 `sum == n` 才表示找到了一种合法拆分,应执行 `ans++`。
第 38 题(单选题,3 分)
⑤ 处应填( )。
正确答案B
解析详情
固定首项 时,需累加的项数满足 ;当 时有 ,求和得到 ,较小的 共贡献 。故总复杂度为 。
三、完善程序(2)绝对众数
一个序列中若某数值出现次数超过序列长度的一半,则称其为绝对众数。输入序列 ,保证存在绝对众数,要求以 空间输出该数。
1 | #include <iostream>
2 | using namespace std;
3 | int n, x, s, cnt;
4 | int main() {
5 | cin >> n;
6 | for (int i = 1; i <= n; i++) {
7 | cin >> x;
8 | if (①) ②;
9 | if (③) ④;
10 | else ⑤;
11 | }
12 | cout << s << endl;
13 | return 0;
14 | }第 39 题(单选题,3 分)
① 处应填( )。
cnt > 0cnt >= 0cnt == 0cnt正确答案C
解析详情
`cnt` 表示当前候选值尚未被抵消的票数;当 `cnt == 0` 时,旧候选已完全抵消,应把当前读入的 `x` 选作新候选。故条件填 `cnt == 0`。
第 40 题(单选题,3 分)
② 处应填( )。
s = cnts = xs = is = n正确答案B
解析详情
触发①说明当前没有有效候选,刚读入的数 `x` 应成为新候选,因此执行 `s = x`。之后同一轮比较 `x == s`,会给新候选记 1 票。
第 41 题(单选题,3 分)
③ 处应填( )。
x < sx > sx == sx == cnt正确答案C
解析详情
读入值与当前候选相同就应增加支持票,不同则用一票相互抵消,所以分支条件必须是 `x == s`。
第 42 题(单选题,3 分)
④ 处应填( )。
cnt++cnt--cnt = icnt = 0正确答案A
解析详情
当 `x == s` 时,当前元素支持候选值,应执行 `cnt++`。特别地,刚在 `cnt == 0` 时选定的新候选也会通过这里把票数从 0 加到 1。
第 43 题(单选题,3 分)
⑤ 处应填( )。
cnt++cnt--cnt = icnt = 0正确答案B
解析详情
当 `x != s` 时,可将当前元素与一个候选元素配对抵消,因此执行 `cnt--`。绝对众数出现次数超过一半,所有异值配对后它仍有剩余票,最终候选 `s` 就是答案。