GESP 客观题评测系统

试卷解析 · 理解每一步

CSP-J 2026 第一轮 AI 模拟卷 2

CSPJ-2026-R1-Mock-AI-2

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

一、单项选择题

(共 15 题,每题 2 分,共 30 分。每题有且仅有一个正确选项。)

第 1 题(单选题,2 分)

若一个文本文件恰好包含 4096 个 ASCII 字符,且每个字符按 1 字节存储,则文件内容占用的位数为( )。

A.
4096
B.
8192
C.
32768
D.
65536

正确答案C

解析详情
答案 C位与字节
思路与推导
  1. 1 字节等于 8 位,所以内容占用 `4096 × 8 = 32768` 位。

第 2 题(单选题,2 分)

在 Linux 终端中,以下命令能以 C++14 标准编译 `main.cpp` 并把可执行文件命名为 `run` 的是( )。

A.
g++ -std=c++14 main.cpp -o run
B.
g++ run -o main.cpp -std=c++14
C.
./main.cpp -std=c++14 run
D.
g++ -o main.cpp run

正确答案A

解析详情
答案 Ag++ 编译命令
思路与推导
  1. `-std=c++14` 指定语言标准,`-o run` 指定输出文件名,因此 A 正确。

第 3 题(单选题,2 分)

执行下列代码后,`t` 的值是( )。 `string s = "algorithm"; string t = s.substr(2, 4);`

A.
gori
B.
gorit
C.
lgo
D.
rith

正确答案A

解析详情
答案 A`string::substr`
思路与推导
  1. 下标 2 的字符是 `g`,从此处取 4 个字符得到 `gori`。

第 4 题(单选题,2 分)

递归函数要保证对所有合法输入都能结束,最关键的条件是( )。

A.
每次递归调用都使用更多局部变量
B.
递归调用必须写在循环内部
C.
递归函数必须返回 `void`
D.
存在不再递归的终止情形,且递归参数逐步接近它

正确答案D

解析详情
答案 D递归终止
思路与推导
  1. 递归必须有基本情形,并且每次调用都让问题规模向基本情形缩小,才能保证有限步结束。

第 5 题(单选题,2 分)

依次执行 `push(3)`、`push(7)`、`pop()`、`push(5)` 后,一个初始为空的栈从栈顶到栈底依次为( )。

A.
3, 5
B.
5, 3
C.
5, 7, 3
D.
3, 7, 5

正确答案B

解析详情
答案 B栈的后进先出
思路与推导
  1. 压入 3、7 后弹出栈顶 7,再压入 5,故栈顶到栈底为 5、3。

第 6 题(单选题,2 分)

一棵非空二叉树共有 18 个结点,其中有 7 个结点恰有两个孩子,则叶结点数为( )。

A.
6
B.
7
C.
8
D.
11

正确答案C

解析详情
答案 C二叉树结点度数关系
思路与推导
  1. 设叶结点数为 `n0`、双孩子结点数为 `n2`,非空二叉树中恒有 `n0 = n2 + 1`,因此叶结点为 8 个。

第 7 题(单选题,2 分)

用欧几里得算法计算 `gcd(252, 198)`,结果为( )。

A.
6
B.
9
C.
18
D.
54

正确答案C

解析详情
答案 C欧几里得算法
思路与推导
  1. `252 mod 198=54`,`198 mod 54=36`,`54 mod 36=18`,`36 mod 18=0`,故最大公约数为 18。

第 8 题(单选题,2 分)

已知 `1≤n≤10^9`,`cnt` 为 `long long`。下列程序片段中,语句 `++cnt` 的执行次数数量级是( )。 `for (int i=1;i<=n;i*=2) for (int j=0;j<i;j++) ++cnt;`

A.
O(log n)
B.
O(n)
C.
O(n log n)
D.
O(n²)

正确答案B

解析详情
答案 B时间复杂度与等比数列
思路与推导
  1. 执行次数为 `1+2+4+...+2^k`,其中 `2^k≤n<2^(k+1)`,和小于 `2n`,故为 O(n)。

第 9 题(单选题,2 分)

执行下列代码后输出为( )。 `void f(int x, int &y){ x += 2; y += x; } int a=3,b=4; f(a,b); cout<<a<<' '<<b;`

A.
3 7
B.
3 9
C.
5 7
D.
5 9

正确答案B

解析详情
答案 B值传递与引用传递
思路与推导
  1. `x` 是 `a` 的副本,变为 5 但不改变 `a`;`y` 引用 `b`,执行 `y += x` 后 `b=9`。

第 10 题(单选题,2 分)

已知字符 `'0'` 到 `'9'` 的 ASCII 码连续。表达式 `'7' - '0'` 的值为( )。

A.
7
B.
0
C.
48
D.
55

正确答案A

解析详情
答案 AASCII 码与字符数字转换
思路与推导
  1. 数字字符连续编码,`'7'` 的编码比 `'0'` 大 7,因此差为整数 7。

第 11 题(单选题,2 分)

用一维动态规划求长度为 `n` 的数组中互不相邻元素的最大和。若 `dp[i]` 表示只考虑前 `i` 个元素的最优值,最合理的转移是( )。

A.
dp[i]=dp[i-1]+a[i]
B.
dp[i]=dp[i-2]
C.
dp[i]=min(dp[i-1],dp[i-2])+a[i]
D.
dp[i]=max(dp[i-1],dp[i-2]+a[i])

正确答案D

解析详情
答案 D简单一维动态规划
思路与推导
  1. 最优方案分为不选第 `i` 个元素和选第 `i` 个元素两类;后者不能选第 `i-1` 个,因此取 `max(dp[i-1],dp[i-2]+a[i])`。

第 12 题(单选题,2 分)

若 `x=26`,则表达式 `x & (x-1)` 的值为( )。

A.
8
B.
16
C.
24
D.
25

正确答案C

解析详情
答案 C位与运算
思路与推导
  1. `26` 的二进制为 `11010`,`25` 为 `11001`,按位与得到 `11000`,即 24。

第 13 题(单选题,2 分)

用字母 `A、B、C、D` 组成长度为 5 的字符串,允许重复,但相邻字符不能相同。这样的字符串共有( )个。

A.
4×3⁴
B.
4⁵
C.
5×4³
D.
4×3×2×1

正确答案A

解析详情
答案 A乘法原理
思路与推导
  1. 第一个位置有 4 种选择,之后每个位置不能等于前一个字符,各有 3 种选择,共 `4×3⁴` 种。

第 14 题(单选题,2 分)

下列程序的输出是( )。 `void g(int n){ if(n==0) return; cout<<n%2; g(n/2); cout<<n%2; } int main(){ g(6); }`

A.
0110
B.
110011
C.
110110
D.
011110

正确答案D

解析详情
答案 D递归展开与输出顺序
思路与推导
  1. 调用顺序为 `g(6), g(3), g(1)`,递归前依次输出 `0,1,1`,回溯时依次输出 `1,1,0`,合为 `011110`。

第 15 题(单选题,2 分)

有容量为 7 的背包,三件物品的(体积,价值)分别为 `(3,4)`、`(4,5)`、`(5,8)`,每件至多选一次。最大总价值为( )。

A.
8
B.
9
C.
12
D.
13

正确答案B

解析详情
答案 B0/1 背包
思路与推导
  1. 可行组合中,前两件总体积 7、价值 9;第三件单独价值 8,不能与其他物品同选,故最大值为 9。

二、阅读程序(1)

输入字符串只含小写英文字母与字符 `#`,且不以 `#` 开头或结尾,也不存在连续的 `#`。判断题正确填 ✓,错误填 ✗。

 1 | #include <algorithm>
 2 | #include <iostream>
 3 | #include <string>
 4 | using namespace std;
 5 | int main() {
 6 |     string s;
 7 |     cin >> s;
 8 |     string ans, part;
 9 |     int pal = 0;
10 |     for (int i = 0; i <= (int)s.size(); ++i) {
11 |         if (i < (int)s.size() && s[i] != '#') {
12 |             part.push_back(s[i]);
13 |         } else {
14 |             string rev = part;
15 |             reverse(rev.begin(), rev.end());
16 |             if (rev == part) ++pal;
17 |             if (!ans.empty()) ans.push_back('#');
18 |             ans += rev;
19 |             part.clear();
20 |         }
21 |     }
22 |     cout << ans << '\n' << pal << '\n';
23 |     return 0;
24 | }

第 16 题(判断题,1 分)

若输入不含字符 `#`,则程序仍会处理整个输入串并输出其逆序串。

正确答案正确

解析详情
答案 正确循环边界与哨兵式处理
思路与推导
  1. 循环执行到 `i==s.size()` 时进入 `else`,把最后一个也是唯一一个分段逆序并加入答案。

第 17 题(判断题,1.5 分)

在题目保证输入不以 `#` 开头、不以 `#` 结尾且不存在连续 `#` 时,变量 `pal` 统计回文分段的个数。

正确答案正确

解析详情
答案 正确回文判定
思路与推导
  1. 每到分隔符或串尾,程序把当前分段复制并逆序;逆序后仍与原串相等恰好表示该分段是回文串。

第 18 题(判断题,1.5 分)

程序输出的第一个字符串与输入字符串长度一定相同。

正确答案正确

解析详情
答案 正确字符串变换不变量
思路与推导
  1. 每个分段只做逆序,字符数不变;每个原有 `#` 在拼接分段时也恰好保留一个,所以总长度不变。

第 19 题(单选题,3 分)

输入为 `ab#level#cde` 时,程序第一行输出为( )。

A.
ba#level#edc
B.
ab#level#cde
C.
edc#level#ba
D.
ba#level#cde

正确答案A

解析详情
答案 A字符串分段模拟
思路与推导
  1. 三个分段分别逆序为 `ba`、`level`、`edc`,并按原分段顺序用 `#` 连接。

第 20 题(单选题,3 分)

输入为 `noon#abc#x#abba` 时,程序第二行输出为( )。

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

正确答案C

解析详情
答案 C回文串判定
思路与推导
  1. `noon`、`x`、`abba` 是回文串,`abc` 不是,因此 `pal=3`。

第 21 题(单选题,3 分)

设输入长度为 `n`。不计输出字符串占用的空间,程序的时间复杂度和额外空间复杂度分别是( )。

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

正确答案A

解析详情
答案 A字符串算法复杂度
思路与推导
  1. 每个字符进入一次 `part`,各分段复制与逆序的总长度为 `n`;`part` 和 `rev` 的最大总规模为 O(n)。

二、阅读程序(2)

输入为一个非空小写英文字母串。判断题正确填 ✓,错误填 ✗。

 1 | #include <iostream>
 2 | #include <string>
 3 | using namespace std;
 4 | string fold(const string &s, int l, int r) {
 5 |     if (l > r) return "";
 6 |     if (l == r) return string(1, s[l]);
 7 |     string mid = fold(s, l + 1, r - 1);
 8 |     if (s[l] < s[r])
 9 |         return s[l] + mid + s[r];
10 |     else
11 |         return s[r] + mid + s[l];
12 | }
13 | int main() {
14 |     string s;
15 |     cin >> s;
16 |     cout << fold(s, 0, (int)s.size() - 1) << '\n';
17 |     return 0;
18 | }

第 22 题(判断题,1.5 分)

对任意非空输入串,`fold` 的返回串长度与输入串长度相同。

正确答案正确

解析详情
答案 正确递归结构与长度不变量
思路与推导
  1. 每层从两端取出两个字符,再递归处理中间部分;奇数长度最后保留中间字符,偶数长度以空串结束,因此没有增删字符。

第 23 题(判断题,1.5 分)

`fold` 的最大递归深度为 O(n)。

正确答案正确

解析详情
答案 正确递归深度
思路与推导
  1. 每次递归令 `l` 增 1、`r` 减 1,区间长度减少 2,所以深度约为 `n/2`,数量级为 O(n)。

第 24 题(判断题,1.5 分)

若输入串本身按字符非降序排列,则输出一定与输入完全相同。

正确答案正确

解析详情
答案 正确递归正确性
思路与推导
  1. 非降序串的每个当前左端字符都小于或等于右端字符。相等时走 `else`,两字符相同,顺序无影响;内部区间也保持非降序,递归后整体不变。

第 25 题(单选题,3 分)

输入为 `cabd` 时,程序输出为( )。

A.
cabd
B.
acdb
C.
bdac
D.
dbac

正确答案A

解析详情
答案 A递归展开
思路与推导
  1. 外层比较 `c` 与 `d`,返回 `c + fold("ab") + d`;内层得到 `ab`,最终输出 `cabd`。

第 26 题(单选题,3 分)

输入为 `dbcae` 时,程序输出为( )。

A.
dbcae
B.
dacbe
C.
eacbd
D.
dbaec

正确答案B

解析详情
答案 B递归字符串构造
思路与推导
  1. 外层 `d<e`,得到 `d...e`;内部两端为 `b` 和 `a`,交换后得到 `a + c + b`,最终为 `dacbe`。

第 27 题(单选题,3 分)

若把程序中的字符串拼接视为按实际字符复制,`fold` 在最坏情况下的时间复杂度最接近( )。

A.
O(log n)
B.
O(n)
C.
O(n log n)
D.
O(n²)

正确答案D

解析详情
答案 D递归与字符串复制复杂度
思路与推导
  1. 递归有 O(n) 层;第 k 层构造长度与当前区间规模同阶的返回串,总复制量为 `n+(n-2)+...`,是 O(n²)。

二、阅读程序(3)

输入为一个仅含数字字符的非空字符串,长度不超过 40。程序把它划分成若干个十进制整数,每段必须在 1~26 之间。判断题正确填 ✓,错误填 ✗。

 1 | #include <iostream>
 2 | #include <string>
 3 | #include <vector>
 4 | using namespace std;
 5 | int main() {
 6 |     string s;
 7 |     cin >> s;
 8 |     int n = s.size();
 9 |     vector<long long> dp(n + 1, 0);
10 |     dp[0] = 1;
11 |     for (int i = 1; i <= n; ++i) {
12 |         if (s[i - 1] != '0') dp[i] += dp[i - 1];
13 |         if (i >= 2) {
14 |             int x = (s[i - 2] - '0') * 10 + s[i - 1] - '0';
15 |             if (10 <= x && x <= 26) dp[i] += dp[i - 2];
16 |         }
17 |     }
18 |     cout << dp[n] << '\n';
19 |     return 0;
20 | }

第 28 题(判断题,1.5 分)

`dp[i]` 表示把前 `i` 个数字字符划分成若干个 1~26 之间整数的方案数。

正确答案正确

解析详情
答案 正确动态规划状态含义
思路与推导
  1. 最后一段可以由一个非零数字组成,或由 10~26 的两位数组成;程序正是把这两类来源累加到 `dp[i]`。

第 29 题(判断题,1.5 分)

初始化 `dp[0]=1` 表示空前缀有一种不选任何段的方案,使后续第一个合法分段能得到正确计数。

正确答案正确

解析详情
答案 正确动态规划初始化
思路与推导
  1. 空前缀作为递推起点有一个空方案;当首位非零时,`dp[1]` 才能从 `dp[0]` 加上 1。

第 30 题(判断题,1.5 分)

若输入串中出现字符 `0`,程序输出一定为 0。

正确答案错误

解析详情
答案 错误数字串 DP 的零处理
思路与推导
  1. `0` 不能单独成段,但可以与前一个字符组成 `10` 或 `20`。例如输入 `10` 时有一种合法划分。

第 31 题(单选题,3 分)

输入为 `12120` 时,程序输出为( )。

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

正确答案C

解析详情
答案 C一维 DP 递推
思路与推导
  1. 依次得到 `dp[0..5]=1,1,2,3,5,3`。末尾 0 只能与前一位组成 20,所以 `dp[5]=dp[3]=3`。

第 32 题(单选题,3 分)

输入为 `3012`。在循环计算过程中,最小的满足 `dp[i]=0` 的正整数 `i` 是( )。

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

正确答案B

解析详情
答案 BDP 不可达状态
思路与推导
  1. 首位 `3` 可以单独成段,所以 `dp[1]=1`;前两位的末尾 `0` 不能单独成段,`30` 也不合法,因此 `dp[2]=0`,首次出现零状态的位置是 2。

第 33 题(单选题,3 分)

设输入长度为 `n`,程序的时间复杂度和额外空间复杂度分别为( )。

A.
O(n),O(1)
B.
O(n),O(n)
C.
O(n²),O(n)
D.
O(2ⁿ),O(n)

正确答案B

解析详情
答案 B动态规划复杂度
思路与推导
  1. 循环执行 n 次,每次只做常数次运算,时间 O(n);数组 `dp` 含 n+1 个元素,额外空间 O(n)。

三、完善程序(1)子序列出现次数

给定两个非空小写字母串 `s` 和 `t`(长度均不超过 30),计算从 `s` 中按原顺序选出若干字符形成 `t` 的方案数。不同下标选择视为不同方案,答案保证在 `long long` 范围内。

#include <iostream>
#include <string>
#include <vector>
using namespace std;
string s, t;
vector<vector<long long>> memo;
long long ways(int i, int j) {
    if (j == (int)t.size()) return ①;
    if (i == (int)s.size()) return ②;
    if (memo[i][j] != -1) return ③;
    long long ans = ways(④, j);
    if (s[i] == t[j]) ans += ways(i + 1, ⑤);
    return memo[i][j] = ans;
}
int main() {
    cin >> s >> t;
    memo.assign(s.size(), vector<long long>(t.size(), -1));
    cout << ways(0, 0) << '\n';
    return 0;
}

第 34 题(单选题,3 分)

当 `j` 已到达目标串末尾时,应把这一条递归路径计为一次成功。为实现这一含义,① 处应填( )。

A.
0
B.
1
C.
i
D.
j

正确答案B

解析详情
答案 B递归计数的成功边界
思路与推导
  1. 当 `j==t.size()` 时,目标串已经全部匹配完成,当前选择形成一种合法方案,应返回 1。

第 35 题(单选题,3 分)

若目标串尚未匹配完而 `i` 已到达源串末尾,这一状态没有可行选法。② 处应填( )。

A.
0
B.
1
C.
s.size()
D.
t.size()

正确答案A

解析详情
答案 A递归计数的失败边界
思路与推导
  1. 目标串尚未匹配完而源串已用尽,不可能再形成匹配,方案数为 0。

第 36 题(单选题,3 分)

缓存表的两个下标分别对应当前源串位置和目标串位置。命中缓存时,③ 处应返回( )。

A.
memo[j][i]
B.
memo[i][j]
C.
memo[i-1][j]
D.
memo[i][j-1]

正确答案B

解析详情
答案 B记忆化搜索状态
思路与推导
  1. 当前子问题由源串位置 `i` 和目标串位置 `j` 唯一确定,已经计算时应直接返回 `memo[i][j]`。

第 37 题(单选题,3 分)

第一类方案跳过 `s[i]` 而不消耗 `t[j]`。为了让源串位置恰好前进一步,④ 处应填( )。

A.
i
B.
i + 1
C.
j + 1
D.
i - 1

正确答案B

解析详情
答案 B子序列递归转移
思路与推导
  1. 第一类方案不选择 `s[i]`,因此源串位置前进到 `i+1`,目标串位置 `j` 不变。

第 38 题(单选题,3 分)

第二类方案选择相等的 `s[i]` 与 `t[j]` 作为一次匹配。此后目标串下标也需前进,所以⑤ 处应填( )。

A.
j
B.
j - 1
C.
j + 1
D.
i + 1

正确答案C

解析详情
答案 C字符匹配转移
思路与推导
  1. 当 `s[i]==t[j]` 并选择该字符时,源串和目标串的下标都应前进 1,因此第二个参数是 `j+1`。

三、完善程序(2)最长回文子序列

给定一个长度为 1~500 的小写字母串,求其最长回文子序列的长度。子序列不要求连续,但必须保持原字符的相对顺序。

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
    string s;
    cin >> s;
    int n = s.size();
    vector<vector<int>> dp(n, vector<int>(n, 0));
    for (int i = 0; i < n; ++i) dp[i][i] = ①;
    for (int len = ②; len <= n; ++len) {
        for (int l = 0; l + len <= n; ++l) {
            int r = ③;
            if (s[l] == s[r])
                dp[l][r] = dp[l + 1][r - 1] + ④;
            else
                dp[l][r] = max(dp[l + 1][r], ⑤);
        }
    }
    cout << dp[0][n - 1] << '\n';
    return 0;
}

第 39 题(单选题,3 分)

初始化所有单字符闭区间时,其最长回文子序列就是该字符本身。① 处应赋值为( )。

A.
0
B.
1
C.
i
D.
n

正确答案B

解析详情
答案 B区间 DP 初始化
思路与推导
  1. 单个字符自身就是长度为 1 的回文子序列,所以 `dp[i][i]=1`。

第 40 题(单选题,3 分)

长度为 1 的区间已经完成初始化。为使转移从最短的未计算区间开始,② 处应填( )。

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

正确答案C

解析详情
答案 C区间 DP 计算顺序
思路与推导
  1. 长度为 1 的区间已经初始化,转移从长度 2 开始,逐步扩大区间。

第 41 题(单选题,3 分)

当前枚举的是左端点为 `l`、长度为 `len` 的闭区间。由 `r-l+1=len`,③ 处应填( )。

A.
l + len
B.
l + len - 1
C.
len - l
D.
n - len

正确答案B

解析详情
答案 B区间端点换算
思路与推导
  1. 长度为 `len`、左端点为 `l` 的闭区间右端点是 `l+len-1`。

第 42 题(单选题,3 分)

当区间两端字符相等时,把它们同时接到内部回文子序列两侧。表示这两个新字符贡献的④ 处应填( )。

A.
1
B.
2
C.
len
D.
dp[l][r]

正确答案B

解析详情
答案 B区间 DP 转移
思路与推导
  1. 当两端字符相等时,可在内部区间最长回文子序列的两端各加入一个字符,长度增加 2。

第 43 题(单选题,3 分)

若两端字符不同,最优解需比较“舍去左端”和“舍去右端”两类。与 `dp[l+1][r]` 配对的⑤ 处应填( )。

A.
dp[l][r - 1]
B.
dp[l + 1][r - 1]
C.
dp[l][r]
D.
dp[l - 1][r]

正确答案A

解析详情
答案 A区间 DP 分类讨论
思路与推导
  1. 两端不相等时,最长回文子序列至少舍去一个端点,因此在 `dp[l+1][r]` 与 `dp[l][r-1]` 中取较大值。