GESP 客观题评测系统

试卷解析 · 理解每一步

普及组 CSP-J 2026 初赛模拟卷 9

CSPJ-2026-R1-Mock-9

试卷解析总览,可直接查看每题答案与解析。

一、单项选择题

第 1 题(单选题,2 分)

在 C++ 中使用 `sort` 函数前,通常需要包含的头文件是( )。

A.
`<string>`
B.
`<algorithm>`
C.
`<queue>`
D.
`<cmath>`

正确答案B

解析详情
答案 BC++ 标准库
思路与推导
  1. `sort` 属于标准算法库,声明在头文件 `<algorithm>` 中。

第 2 题(单选题,2 分)

客户端和服务器之间完成 TCP 连接建立需要通过( )次握手。

A.
1
B.
2
C.
3
D.
4

正确答案C

解析详情
答案 CTCP 三次握手
思路与推导
  1. 客户端发送 SYN,服务器回复 SYN+ACK,客户端再发送 ACK,共交换 3 次报文后建立 TCP 连接。

第 3 题(单选题,2 分)

下列( )两种语言都是典型的编译型语言。

A.
C++、Python
B.
Python、Java
C.
Java、MATLAB
D.
Pascal、C++

正确答案D

解析详情
答案 D编译型语言
思路与推导
  1. Pascal 和 C++ 的源程序通常先由编译器整体翻译为目标程序,再执行生成的程序,二者都是典型的编译型语言。

第 4 题(单选题,2 分)

二进制数 0.10110.1011 对应的八进制数是( )。

A.
0.230.23
B.
0.510.51
C.
0.540.54
D.
0.68750.6875

正确答案C

解析详情
答案 C二进制与八进制转换
思路与推导
  1. 从小数点向右每 3 位分组并补零:0.10112=0.101 10020.1011_2=0.101\,100_2。1012=5101_2=5、1002=4100_2=4,所以结果为 0.5480.54_8。

第 5 题(单选题,2 分)

公告只包含 A、B、C、D 四个字符,出现频率分别为 20%、30%、40%、10%。使用哈夫曼编码,( )的编码长度一定最短。

A.
A
B.
B
C.
C
D.
D

正确答案C

解析详情
答案 C哈夫曼编码
思路与推导
  1. 先合并频率最低的 D(10%) 与 A(20%) 得 30%,再合并两个 30%,最后由 C(40%) 与 60% 的结点组成根。C 直接连在根下,码长为 1,必定最短。

第 6 题(单选题,2 分)

扫描一张 4 英寸 × 6 英寸的彩色照片,分辨率为 300 dpi,使用 24 位真彩色且不压缩,存储容量约为( )。

A.
2.07MB
B.
4.15MB
C.
6.22MB
D.
8.29MB

正确答案C

解析详情
答案 C位图存储容量
思路与推导
  1. 像素数为 (4×300)(6×300)=2,160,000(4\times300)(6\times300)=2{,}160{,}000,24 位即每像素 3 字节。容量为 6,480,0006{,}480{,}000 字节,按二进制单位折算约 6.2 MB6.2\text{ MB},最接近 6.22MB。

第 7 题(单选题,2 分)

在 Linux 终端中,要在当前目录及其子目录的文本文件里递归查找字符串 `CSPJ`,最合适的命令是( )。

A.
`pwd CSPJ`
B.
`mkdir CSPJ`
C.
`ls CSPJ`
D.
`grep -R CSPJ .`

正确答案D

解析详情
答案 DLinux 文本搜索
思路与推导
  1. `grep -R CSPJ .` 会从当前目录开始递归搜索包含指定字符串的文件内容。

第 8 题(单选题,2 分)

假设布尔变量 aa 为真、bb 为假、cc 为真,那么表达式 (a∧b)∨(c∧¬b)(a\land b)\lor(c\land\lnot b) 的结果是( )。

A.
真
B.
假
C.
无法确定
D.
语法错误

正确答案A

解析详情
答案 A布尔表达式求值
思路与推导
  1. a∧b=真∧假=假a\land b=\text{真}\land\text{假}=\text{假};c∧¬b=真∧真=真c\land\lnot b=\text{真}\land\text{真}=\text{真}。两部分取或得到真。

第 9 题(单选题,2 分)

在单链表中,指针 `p` 指向待删除结点的前驱,且 `p->next` 一定存在。正确删除 `p->next` 所指结点的代码是( )。

A.
`p = p->next;`
B.
`delete p;`
C.
`Node* q = p->next; p->next = q->next; delete q;`
D.
`p->next = nullptr;`

正确答案C

解析详情
答案 C单链表删除
思路与推导
  1. 先用 `q` 保存待删除结点,再让前驱 `p` 越过该结点指向 `q->next`,最后释放 `q`,因此 C 正确。

第 10 题(单选题,2 分)

一棵二叉树,中序遍历的结果为 `abc`,那么这棵二叉树有( )种不同的形态。

A.
2
B.
3
C.
4
D.
5

正确答案D

解析详情
答案 D二叉树形态与卡特兰数
思路与推导
  1. 固定 3 个结点的中序次序后,不同二叉树形态数为第 3 个卡特兰数:C3=14(63)=5C_3=\frac{1}{4}\binom{6}{3}=5。

第 11 题(单选题,2 分)

给定数字 0、1、3、4、5、9,每个数字最多用一次,可能组成( )个 4 位偶数。

A.
360
B.
300
C.
192
D.
108

正确答案D

解析详情
答案 D分类计数与排列
思路与推导
  1. 末位为 0 时有 5×4×3=605\times4\times3=60 个;末位为 4 时,首位有 4 种非零选择,中间两位有 4×34\times3 种,共 48 个。总数为 60+48=10860+48=108。

第 12 题(单选题,2 分)

以下代码的输出是( )。

int a = 5, b = 3, c = 0;
c = a++ + ++b;
cout << a << ' ' << b << ' ' << c;
A.
`5 3 8`
B.
`5 4 8`
C.
`6 4 9`
D.
`6 4 10`

正确答案C

解析详情
答案 C自增运算符
思路与推导
  1. 「a++」 先参与运算取值 5,再使 「a=6」;「++b」 先使 「b=4」,再取值 4。因此 「c=5+4=9」,输出 「6 4 9」。

第 13 题(单选题,2 分)

定义 f(n)f(n) 为 nn 的各位数字之和。数字根 dr(n)=f(f(⋯f(n)⋯ ))dr(n)=f(f(\cdots f(n)\cdots))(直到结果不再变化),则 dr(2026)dr(2026) 的结果是( )。

A.
0
B.
1
C.
9
D.
10

正确答案B

解析详情
答案 B数字根
思路与推导
  1. f(2026)=2+0+2+6=10f(2026)=2+0+2+6=10,继续计算 f(10)=1f(10)=1;1 已是个位数,因此 dr(2026)=1dr(2026)=1。

第 14 题(单选题,2 分)

在 NOI Linux 终端中,要删除名为 `old.exe` 的文件,应该使用命令( )。

A.
`del old.exe`
B.
`rm old.exe`
C.
`remove old.exe`
D.
`delete old.exe`

正确答案B

解析详情
答案 BLinux 文件命令
思路与推导
  1. Linux 使用 「rm 文件名」 删除普通文件,因此删除 「old.exe」 的命令是 「rm old.exe」。

第 15 题(单选题,2 分)

以下代码的输出是( )。

const int N = 5;
int arr[N] = {10, 20, 30, 40, 50};
int *p = arr;
int sum = 0;
for (int i = 0; i < N; i++) {
    sum += (*p)++;
}
cout << sum;
A.
10
B.
50
C.
60
D.
150

正确答案C

解析详情
答案 C指针解引用与后置自增
思路与推导
  1. 「p」 始终指向 「arr[0]」,循环中的 「(*p)++」 每次先把当前值加入 「sum」,再令该元素加 1。五次加入的值依次为 10、11、12、13、14,总和为 60。

二、阅读程序(1)

1 | #include <bits/stdc++.h>
2 | #define int long long
3 | using namespace std;
4 | int f(int x) {
5 |     int res = 0;
6 |     while (x) {
7 |         res += x % 10;
8 |         x /= 10;
9 |     }
10 |     return res;
11 | }
12 | int solve1(int x) {
13 |     if (x < 10) return x;
14 |     return solve1(f(x));
15 | }
16 | int solve2(int x) {
17 |     return (x - 1) % 9 + 1;
18 | }
19 | signed main() {
20 |     int n;
21 |     cin >> n;
22 |     cout << solve1(n) << ' ' << solve2(n) << endl;
23 |     return 0;
24 | }

第 16 题(判断题,2 分)

输入 1234 时,输出结果为 `1 1`。( )

正确答案正确

解析详情
答案 正确数字根与递归追踪
思路与推导
  1. 「f(1234)=10」,继续有 「f(10)=1」,所以 「solve1(1234)=1」;「solve2(1234)=(1234-1)%9+1=1」,输出为 「1 1」。

第 17 题(判断题,2 分)

输入的数为负数时,输出的两个数肯定不一致。( )

正确答案错误

解析详情
答案 错误负数取模与函数边界
思路与推导
  1. 反例取 「x=-1」:「solve1(-1)」 因 「x<10」 直接返回 -1;C++ 中 「(-2)%9=-2」,故 「solve2(-1)=-1」,两个输出相同。

第 18 题(判断题,2 分)

将 `solve1()` 的内容改成下面的代码,其功能不变。( )

while (x >= 10) x = f(x);
return x;

正确答案正确

解析详情
答案 正确递归与迭代等价转换
思路与推导
  1. 原函数在 「x>=10」 时递归调用 「solve1(f(x))」,直到 「x<10」 返回;循环版本重复执行同样的 「x=f(x)」,终止条件和最终返回值完全一致。

第 19 题(单选题,3 分)

若输入的 nn 为一个身份证号码(保证没有 X),则下列说法中正确的是( )。

A.
数值超过 `int` 类型的最大值,产生溢出
B.
数值太大,会导致 `solve1()` 函数递归深度过大,进而导致栈溢出
C.
程序可以正常运行,但实际输出结果不对
D.
程序可以正常运行,输出结果也正确

正确答案D

解析详情
答案 D整数范围与递归深度
思路与推导
  1. 「#define int long long」 使 「n」 为 64 位有符号整数;18 位身份证号码小于约 9.22×10189.22\times10^{18} 的上限。首次数位和至多 162,随后很快降为个位数,两个函数均可正常得到数字根。

第 20 题(单选题,4 分)

函数 `solve1()` 和 `solve2()` 的时间复杂度分别为( )。

A.
O(log⁡log⁡n),O(1)O(\log\log n),O(1)
B.
O(log⁡n),O(1)O(\log n),O(1)
C.
O(1),O(log⁡log⁡n)O(1),O(\log\log n)
D.
O(1),O(log⁡n)O(1),O(\log n)

正确答案A

解析详情
答案 A数字根算法复杂度
思路与推导
  1. 按命题预期只计数字和后的递归压缩层数,位数会从 log⁡n\log n 迅速降到 log⁡log⁡n\log\log n 量级,因此记为 O(log⁡log⁡n)O(\log\log n);公式法 「solve2」 只做常数次运算,为 O(1)O(1)。

  2. 若把 「f(n)」 扫描全部十进制位的代价计入,「solve1」 实际为 Θ(log⁡n)\Theta(\log n),故答案 A 的复杂度口径需结合原卷确认。

二、阅读程序(2)

1 | #include <iostream>
2 | #include <iomanip>
3 | #include <cmath>
4 | using namespace std;
5 | const double ERR = 1e-7;
6 | const double CMP_EPS = 1e-12;
7 |
8 | int main() {
9 |     double x;
10 |     scanf("%lf", &x); // 保证输入是非负实数
11 |     double left = 0, right = max(1.0, x);
12 |     while (right - left > ERR) {
13 |         double mid = (left + right) / 2;
14 |         double diff = mid * mid - x;
15 |         if (fabs(diff) <= CMP_EPS) {
16 |             left = mid;
17 |             break;
18 |         }
19 |         if (diff < 0) {
20 |             left = mid;
21 |         } else {
22 |             right = mid;
23 |         }
24 |     }
25 |     printf("%.6lf\n", left);
26 |     return 0;
27 | }

第 21 题(判断题,2 分)

该程序使用二分法求非负实数的算术平方根。( )

正确答案正确

解析详情
答案 正确实数二分与平方根
思路与推导
  1. 区间初始为 [0,max⁡(1,x)][0,\max(1,x)],包含 x\sqrt{x};每次根据 「mid*mid-x」 的正负保留含根的一半区间,最终 「left」 逼近 x\sqrt{x}。

第 22 题(判断题,2 分)

将 `while` 循环改为 `while (right != left)`,程序也可以正常输出,但结果不够精确。( )

正确答案错误

解析详情
答案 错误浮点数二分终止条件
思路与推导
  1. 浮点数精度有限,区间很小时 「mid」 可能舍入成 「left」 或 「right」,赋值后区间不再缩小而两端仍不相等,「right != left」 可能导致死循环。

第 23 题(判断题,2 分)

若输入的数为 xx,则该程序的时间复杂度为 O(log⁡x)O(\log x)。( )

正确答案正确

解析详情
答案 正确二分法时间复杂度
思路与推导
  1. 初始区间长度为 max⁡(1,x)\max(1,x),每轮减半,迭代次数约为 log⁡2(max⁡(1,x)/ERR)\log_2(\max(1,x)/ERR)。当 「ERR」 为常数且 x≥1x\ge1 时可写为 O(log⁡x)O(\log x)。

第 24 题(单选题,3 分)

当输入 0.625 时,输出结果是( )。

A.
0.025000
B.
0.250000
C.
0.790569
D.
0.800569

正确答案C

解析详情
答案 C平方根近似计算
思路与推导
  1. 程序二分逼近 0.625\sqrt{0.625},而 0.625≈0.790569415\sqrt{0.625}\approx0.790569415。按 「%.6lf」 保留 6 位小数,输出 「0.790569」。

第 25 题(单选题,4 分)

`ERR` 的值修改为( ),会导致输出结果有误差。

A.
`1e-6`
B.
`1e-7`
C.
`1e-8`
D.
`1e-9`

正确答案A

解析详情
答案 A误差界与小数输出
思路与推导
  1. 输出保留 6 位小数,要稳定舍入通常需把绝对误差控制到小于约 0.5×10−60.5\times10^{-6}。

  2. 「ERR=1e-6」 时区间宽度仍可能造成末位舍入错误;其余阈值更小,精度更充分。

二、阅读程序(3)

1 | #include <bits/stdc++.h>
2 | using namespace std;
3 | typedef long long ll;
4 | const ll N = 21;
5 | ll n, m, S[N][N];
6 |
7 | int main() {
8 |     cin >> n >> m; // 保证 n、m 是不大于 20 的正整数
9 |     if (n < m) {
10 |         cout << 0 << endl;
11 |         return 0;
12 |     }
13 |     if (n == m && m == 0) {
14 |         cout << 1 << endl;
15 |         return 0;
16 |     }
17 |
18 |     for (int i = 1; i <= n; i++) S[i][1] = 1;
19 |     for (int j = 2; j <= m; j++)
20 |         for (int i = j; i <= n; i++)
21 |             S[i][j] = S[i - 1][j - 1] + j * S[i - 1][j];
22 |     cout << S[n][m] << endl;
23 |     return 0;
24 | }

第 26 题(判断题,2 分)

若输入 n=5,m=3n=5,m=3,则程序输出结果为 26。( )

正确答案错误

解析详情
答案 错误第二类斯特林数递推
思路与推导
  1. 递推为 S(i,j)=S(i−1,j−1)+jS(i−1,j)S(i,j)=S(i-1,j-1)+jS(i-1,j)。由 S(4,2)=7S(4,2)=7、S(4,3)=6S(4,3)=6 得 S(5,3)=7+3×6=25S(5,3)=7+3\times6=25,不是 26。

第 27 题(判断题,2 分)

程序计算将 nn 个不同元素划分成 mm 个无序集合的方案数。( )

正确答案错误

解析详情
答案 错误第二类斯特林数的组合意义
思路与推导
  1. 程序的递推 S(n,m)=S(n−1,m−1)+mS(n−1,m)S(n,m)=S(n-1,m-1)+mS(n-1,m) 计算把 nn 个不同元素划分为 mm 个非空、无标号集合的方案数。

  2. 题干只说“mm 个无序集合”,没有给出每个集合必须非空这一必要限制,描述不完整,因此按原卷答案判为错误。

第 28 题(判断题,2 分)

若将第 22 行改成下面的代码,则程序计算将 nn 个不同元素划分到不超过 mm 个非空集合的方案总数。( )

ll res = 0;
for (int i = 1; i <= m; i++) res += S[n][i];
cout << res << endl;

正确答案正确

解析详情
答案 正确第二类斯特林数求和
思路与推导
  1. 「S[n][i]」 表示恰好划分为 ii 个非空集合的方案数。将 i=1i=1 到 mm 的值相加,恰好覆盖划分为不超过 mm 个非空集合的全部情况,且各情况互不重复。

第 29 题(单选题,4 分)

若输入 n=7,m=3n=7,m=3,则程序输出结果为( )。

A.
105
B.
140
C.
301
D.
305

正确答案C

解析详情
答案 C第二类斯特林数计算
思路与推导
  1. 递推到 n=6n=6 可得 S(6,2)=31S(6,2)=31、S(6,3)=90S(6,3)=90,于是 S(7,3)=S(6,2)+3S(6,3)=31+270=301S(7,3)=S(6,2)+3S(6,3)=31+270=301。

第 30 题(单选题,4 分)

若将内层循环条件 `for (int i = j; i <= n; i++)` 改为 `for (int i = 1; i <= n; i++)`,则程序( )。

A.
结果不变
B.
结果可能错误,因为会计算多余的状态
C.
结果可能错误,因为会计算无效状态(i<ji<j)
D.
运行出错,因为数组访问越界

正确答案A

解析详情
答案 A动态规划无效状态
思路与推导
  1. 数组为全局变量,i<ji<j 的状态初值均为 0;按 jj 递增、ii 递增计算时,这些无效状态仍由零状态推出 0。它们虽被多算,却不会影响后续 i≥ji\ge j 的有效状态,所以结果不变。

三、完善程序(1)差分数组

(差分数组)给定一个长度为 nn、初始值全为 0 的序列。进行 mm 次操作,每次把闭区间 [l,r][l,r] 中的所有数增加 xx,最后输出整个序列。保证 1≤l≤r≤n1\le l\le r\le n。

1 | #include <iostream>
2 | #include <vector>
3 | using namespace std;
4 | int main() {
5 |     int n, m;
6 |     cin >> n >> m;
7 |     vector<long long> diff(①, 0), a(n + 1, 0);
8 |     for (int k = 0; k < ②; ++k) {
9 |         int l, r;
10 |         long long x;
11 |         cin >> l >> r >> x;
12 |         ③;
13 |         ④;
14 |     }
15 |     for (int i = 1; i <= n; ++i) {
16 |         a[i] = ⑤;
17 |         cout << a[i] << (i == n ? '\n' : ' ');
18 |     }
19 |     return 0;
20 | }

第 31 题(单选题,3 分)

① 处应填( )。

A.
n
B.
n - 1
C.
n + 1
D.
n + 2

正确答案D

解析详情
答案 D差分数组边界
思路与推导
  1. 操作会访问 `diff[r+1]`,当 `r=n` 时需要访问下标 `n+1`,所以数组长度至少为 `n+2`。

第 32 题(单选题,3 分)

② 处应填( )。

A.
n
B.
n + m
C.
m
D.
n * m

正确答案C

解析详情
答案 C循环次数
思路与推导
  1. 输入包含 `m` 次区间修改,因此操作循环应执行 `m` 次。

第 33 题(单选题,3 分)

③ 处应填( )。

A.
diff[r] += x
B.
diff[l] -= x
C.
a[l] += x
D.
diff[l] += x

正确答案D

解析详情
答案 D差分区间修改
思路与推导
  1. 让区间从位置 `l` 开始增加 `x`,应执行 `diff[l] += x`。

第 34 题(单选题,3 分)

④ 处应填( )。

A.
diff[r] -= x
B.
diff[l + 1] -= x
C.
diff[r + 1] += x
D.
diff[r + 1] -= x

正确答案D

解析详情
答案 D差分区间修改
思路与推导
  1. 区间影响在 `r` 之后结束,因此应在 `r+1` 位置减去 `x`。

第 35 题(单选题,3 分)

⑤ 处应填( )。

A.
diff[i - 1] + a[i]
B.
a[i - 1] + diff[i]
C.
a[i - 1] - diff[i]
D.
diff[i]

正确答案B

解析详情
答案 B差分还原
思路与推导
  1. 原数组等于差分数组的前缀和,所以 `a[i] = a[i-1] + diff[i]`。

三、完善程序(2)高精度除以单精度

当大数超过普通整数范围时,使用数组模拟手工除法,从高位到低位逐位计算,输出大数除以普通整数所得的商和余数。

1 | #include <iostream>
2 | #include <string>
3 | #define SIZE 209
4 | using namespace std;
5 | void converts(int *a, string s) {
6 |     int i, len = s.size();
7 |     for (i = 0; i < len; i++) a[i] = s[len - i - 1] - '0';
8 |     for (; i < SIZE; i++) a[i] = 0;
9 | }
10 | void div(int *a, int n) {
11 |     for (int i = SIZE - 1, c = 0; i >= 0; i--) {
12 |         c = ①;
13 |         a[i] = c / n;
14 |     }
15 | }
16 |
17 | int mod(int *a, int n) {
18 |     int r = 0;
19 |     for (int i = SIZE - 1; i >= 0; i--)
20 |         r = (r * 10 + a[i]) % n;
21 |     return r;
22 | }
23 | void print(int *a) {
24 |     int i;
25 |     for (i = SIZE - 1; i > 0; i--)
26 |         if (a[i] > 0) break;
27 |     for (②) cout << a[i];
28 |     cout << endl;
29 | }
30 | int x[SIZE];
31 |
32 | int main() {
33 |     string s;
34 |     int n;
35 |     cin >> s >> n;
36 |     ③;
37 |     int r;
38 |     ④;
39 |     ⑤;
40 |     print(x);
41 |     cout << r << endl;
42 |     return 0;
43 | }

第 36 题(单选题,3 分)

① 处应填( )。

A.
c / n + a[i]
B.
c % n + a[i]
C.
c / n * 10 + a[i]
D.
c % n * 10 + a[i]

正确答案D

解析详情
答案 D高精度逐位除法
思路与推导
  1. 处理当前十进制位前,应取上一前缀除以 「n」 的余数 「c%n」,乘 10 后拼接当前位 「a[i]」,即 「c=c%n*10+a[i]」;随后 「c/n」 就是当前商位。

第 37 题(单选题,3 分)

② 处应填( )。

A.
i - 1; i >= 0; i--
B.
i - 1; i > 0; i--
C.
; i >= 0; i--
D.
; i > 0; i--

正确答案C

解析详情
答案 C高精度数输出
思路与推导
  1. 前一个循环结束时,「i」 已停在商的最高非零位;输出循环应复用当前 「i」,从该位一直打印到下标 0,因此初始化部分留空,条件为 「i>=0」。

第 38 题(单选题,3 分)

③ 处应填( )。

A.
converts(x, n)
B.
converts(n, x)
C.
converts(x, s)
D.
converts(s, x)

正确答案C

解析详情
答案 C函数参数匹配
思路与推导
  1. 「converts(int *a,string s)」 的第一个参数接收数字数组,第二个参数接收输入字符串。主程序应把字符串 「s」 逆序转换到数组 「x」,所以调用 「converts(x,s)」。

第 39 题(单选题,3 分)

④ 处应填( )。

A.
mod(x, n)
B.
div(x, n)
C.
r = mod(x, n)
D.
r = div(x, n)

正确答案C

解析详情
答案 C高精度除法调用顺序
思路与推导
  1. 「mod(x,n)」 依据原被除数数组计算余数并返回,故先执行 「r=mod(x,n)」 保存余数。若先调用 「div」,数组 「x」 会被原地改写为商,之后无法得到原数的余数。

第 40 题(单选题,3 分)

⑤ 处应填( )。

A.
mod(x, n)
B.
div(x, n)
C.
r = mod(x, n)
D.
r = div(x, n)

正确答案B

解析详情
答案 B高精度除法流程
思路与推导
  1. 余数已由上一空保存到 「r」 后,需要调用 「div(x,n)」,从高位到低位把数组 「x」 原地改成商;随后 「print(x)」 才能输出正确的商。