CSP-J 2026 第一轮答案解析
2026-09-28 21:03:12
发布于:浙江
选择题(每题 2 分)
- 下列 C++ 数据类型中,能够精确存储 这个整数的是()。
A.floatB.long longC.doubleD.int
答案:B
解析: 只有 long long 存的下这个数。
- 十六进制数
2F5转换成八进制数是()。
A.1364 B.1635 C.1405 D.1365
答案:D
解析: 手算一遍就知道。
- 执行下列 C++ 代码,输出是()。
int a = 7, b = 3;
std::cout << a / b * b + a % b;
A.9 B.10 C.7 D.6
答案:C
解析: C++ 整数除法自动向下取整,7 / 3 * 3 = 6,7 % 3 = 1,6 + 1 = 7。
- 初始时栈为空,将 1、2、3、4 依次入栈,入栈过程中允许随时出栈。下列出栈序列中不可能出现的是( )。
A.2,4,3,1
B.1,2,3,4
C.3,1,2,4
D.1,4,3,2
答案:C
解析: 栈属于后进先出,C 选项弹出 3 时,栈内 2 在 1 上面,不可能先弹出 1 后弹出 2;其他选项均正确。
- 一棵有 100 个结点的完全二叉树,其叶子结点个数是( )。
A.49 B.50 C.64 D.51
答案:B
解析: 按照 1~100 给这些节点从上到下,左到右排号,节点 n 的左孩子编号为 2n,所以有左孩子的节点应该是 1~50,则 51~100 都是叶子节点。故选 B。
也可直接记公式:
在完全二叉树中,当节点数 n 为偶数时,度为 0 的节点即叶子节点个数为 ,度为 1 的节点个数为 1,度为 2 的节点个数为 ;
否则,当节点数 n 为奇数时,度为 0 的节点即叶子节点个数为 ,度为 1 的节点个数为 0,度为 2 的节点个数为 。
- 执行下列代码后
s的值是( )。
int s = 0;
for (int i = 1; i <= 100; i++)
if (i % 3 == 0 || i % 5 == 0)
s += i;
A.3048 B.2733 C.2318 D.2418
答案:D
解析: s 算的是 1~100 内 3 的倍数和 5 的倍数,只需要计算
但是会有重复的(能被 15 整除的),所以再减掉
利用等差数列公式计算即可,结果
7.上楼梯每步可上 1 级、2 级或 3 级,从地面(可视为第 0 级)走到第 8 级台阶共有多少种不同走法( )。
A.44 B.121 C.149 D.81
答案:D
解析: 这是一个递推数组,状态转移方程为
其中, ,求 。
解得 。
8.下图为 网格,行号、列号均从 0 开始,# 为障碍,. 为可通行格:
S . . # .
. . . # .
. . . # .
# # . . E
. . . # .
从 S 出发做广度优先搜索(BFS):初始时把 S 入队;每次取出队首格子,按“上、下、左、右”(上=行号减 1,下=行号加 1,左=列号减 1,右=列号加 1)的顺序遍历它的四个相邻格子,越界、障碍或已访问的格子跳过,其余格子标记为已访问并入队。当 E 第一次入队时,已经入队过的格子(含 S 和 E)共有多少个( )。
A.15 B.12 C.14 D.13
答案:C
解析: 同样是手算,题目说啥就做啥。
这里给出模拟结果:
当 S 和 E 入队时,已入队 14 个位置,数字为入队顺序编号,-1 表示未抵达。
1 3 6 -1 -1
2 5 8 -1 -1
4 7 9 -1 -1
-1 -1 10 12 14
-1 13 11 -1 -1
9.满足 且 的正整数 共有多少个( )。
A.8 B.6 C.4 D.5
答案:B
解析: 不厌其烦的话,可以一个一个试过去,效率极低,不推荐。
可以令 且 , ,则 与 10 互质。
的所有取值为 。
10.某国硬币面值为 1 元、4 元、6 元且数量不限,凑出 9 元最少需要多少枚( )。
A.3 B.4 C.5 D.2
答案:A
解析: 显然,只需要 1 张 1 元和 2 张 4 元,贪心思想在这里是行不通的。
11.执行以下代码,输出是( )。
int a[5] = {1, 3, 5, 7, 9};
int *p = a + 2;
*(p - 1) = p[0] + p[2];
p[1] = *(a + 1) - a[0];
cout << a[1] << "," << a[3];
A.14,13
B.8,13
C.14,7
D.14,2
答案:A
解析: 看上去还可以找相同点蒙这题,但是只会蒙是不行的。
实际上指针 p 指向了 a + 2 的地址,*(p - 1) 是在解引用 a + 2 - 1 ,等价于 a[1] ,p[i] 等价于 a[i + 2] 。
代码等价于下面这段:
int a[5] = {1, 3, 5, 7, 9};
a[1] = a[2] + a[4];
a[3] = a[1] - a[0];
cout << a[1] << "," << a[3];
输出结果为 14,13 。
12.在含 1000 个互不相同元素的升序数组中,用二分法查找给定值(返回元素位置或报告不存在),最坏情况下需要与数组元素比较多少次( )。
A.500 B.9 C.11 D.10
答案:D
解析: 二分查找法每次排除一半元素,查找 次最多排除 个元素,则 个元素最多需要 次,其中数学符号 表示将数 向上取整。 。故选 D。
13.数组 的前缀和数组 (即 )满足 。则 的值是( )。
A.252 B.310 C.58 D.61
答案:C
解析: 美妙的是这题貌似也能蒙,但还是记得那句话,算出来的才是对的。
求 的值可以对 求差分,根据前缀和公式推出 ,则只需求出 和 。
题目已给出公式,只需代入计算:
故选 C。
14.数轴上有 7 个点,坐标分别为 1、3、4、7、10、15、20。在数轴上选取一个整数坐标点 P,使 P 到这 7 个点的距离之和最小,这个最小距离和是( )。
A.37 B.42 C.40 D.38
答案:A
解析: 本题属于初中数学较基础的内容,令点 离其他所有点距离和最短,只需要牢记以下两点:
- 当点数 为奇数,则 需要设置在第 个点的位置。
- 否则,当点数 为偶数,则 需要设置在第 个点至第 个点之间的任意位置。
本题点数为奇数,则 设置在第 即第 个点的位置 ,最短距离和
15.一个无向图有 10 个顶点,其中 4 个顶点的度为 3,其余顶点的度均为 4,则该图的边数是( )。
A.36 B.18 C.17 D.20
答案:B
解析: 无向图顶点的总度数等于边数的 2 倍,度数 ,则边数是 。故选 B。
程序阅读题
判断题正确为 A,错误为 B,默认分值 1.5;选择题默认分值 3 分。
1.阅读以下程序:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int x = 1, y = 1;
while (n > 0) {
if (n % 2 == 0) {
++x;
} else {
++x;
++y;
}
n = n / 2;
}
cout << x << ' ' << y << endl;
return 0;
}
输入的 均为不超过 的非负整数。
(1)(1 分)当输入为 3 时,程序输出为 3 3。( )
A.正确 B.错误
(2)将第 11 行的 ++x; 删除后,程序输出的两个数一定相等。( )
A.正确 B.错误
(3)假设输入为非负整数,则程序输出的第一个数一定不小于第二个数。( )
A.正确 B.错误
(4)将第 7 行的 while (n > 0) 改为 while (n >= 0) 后,程序可能出现的问题是( )。
A.陷入死循环 B.输出结果比原来大 C.输出结果比原来小 D.输出结果保持不变
(5)当输入为 6 时,输出为( )。
A.3 3 B. 4 2 C.4 3 D.5 2
(6)若输入 依次取遍 中的所有整数,则程序输出的第二个数恰好为 的次数为( )。
A.16 B.30 C.31 D.32
答案:A B A A C C
解析:
(1)程序输出的第一个数 相当于 的二进制位数 ,第二个数 相当于 的二进制下 的个数 ,可以模拟一下( 和 都是从 开始)。故选 A。
| 循环次数 | |||
|---|---|---|---|
(2)修改后, 意义改为 的二进制下 的个数 , 不变。
显然, 不一定成立,以 为例,它的二进制是 ,模拟过程:
| 循环次数 | |||
|---|---|---|---|
则 。故选 B。
(3)第一题得出的结论:
程序输出的第一个数 相当于 的二进制位数 ,第二个数 相当于 的二进制下 的个数 。
它间接证明 ,因为二进制总位数一定不小于二进制表示下 的个数。故选 A。
(4)根据题中条件,当 变为 时,每次 n /= 2 执行后, 仍为 ,导致死循环。故选 A。
(5) 的二进制表示为 ,模拟过程:
| 循环次数 | |||
|---|---|---|---|
则 。故选 C。
(6)输出的 恰好为 所给出的隐含条件为 的二进制表示下 的个数恰好为 ,可以发现 一定是 ,在题中范围内,可以是 ,共 31 个。故选 C。
2.阅读以下程序:
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int a[100007], b[100007], c[100007], carry[100007];
string input_str;
int a_len, b_len;
int main() {
cin >> input_str;
a_len = input_str.size();
for (int i = 0; i < a_len; i++) {
a[i] = input_str[a_len - i - 1] - '0';
}
cin >> input_str;
b_len = input_str.size();
for (int i = 0; i < b_len; i++) {
b[i] = input_str[b_len - i - 1] - '0';
}
carry[0] = 0;
for (int i = 0; i < max(a_len, b_len) + 1; i++) {
c[i] = a[i] + b[i] + carry[i];
if (c[i] >= 10) {
carry[i + 1] = 1;
c[i] -= 10;
} else {
carry[i + 1] = 0;
}
}
for (int i = max(a_len, b_len); i >= 0; i--) {
cout << c[i];
}
cout << endl;
return 0;
}
(1)当输入为 123 456 时,程序输出为 0579。( )
A.正确 B.错误
(2)假设输入的两个数均不含前导零,则程序输出的结果也一定不会含有前导零。( )
A.正确 B.错误
(3)将第 21 行改为 c[i] = a[i] + b[i]; 后,程序输出的结果一定比原来的结果小。( )
A.正确 B.错误
(4)当输入为 12345 678 时,输出为( )。
A.012923 B.013023 C.13023 D.130230
(5)将第 22 行的 if (c[i] >= 10) 改为 if (c[i] > 10) 后,当输入为 95 15 时,输出为( )。
A.01010 B.110 C.140 D.1410
(6)假设输入的两个数均为 位正整数(不含前导零),且它们的和小于
,则程序输出的字符串一定满足( )。
A.第一个字符一定不为 '0'
B.长度一定为
C.长度一定为 ,且第一个字符为 '0'
D.长度可能为
答案:A B B B A C
解析:为避免啰嗦,程序中的 a_len 用 n 代替,b_len 用 m 代替。
程序变量说明:
a_len 表示 第一个数的位数,b_len 表示 第二个数的位数;
a 数组和 b 数组分别存放输入的两个数(倒序存放,低位在 a[0],便于计算;
c 数组存放结果,carry 数组处理进位。
(1)输出 c 数组时,从 c[max(n, m)] 到 c[0] 固定输出 max(n, m) + 1 位,123 + 456 的运算中没有向 c[max(n, m)] 进位,所以最高位是 0 ,其余位正常加法运算,得 ,加上一位前导零为 。故选 A。
(2)根据上题答案即可选出本题答案。两个整数最大长度为 max(n, m) ,若最终没有向第 max(n, m) + 1 位进位,它的值就是 0 。而程序又没有去除前导零,所以输出的数存在有前导零。故选 B。
(3)修改后的程序忽略了 carry 数组,它的作用是处理向上的进位,忽略后可能导致少进位。但是若输入的两个数无法产生任何进位,carry 数组未存放任何数据,输出的结果就与原结果一致。故选 B。
(4)先计算算式的值: 。最高位没有产生进位,在最高位补一个前导零,输出为 013023 。故选 B。
(5)修改后的程序判断需要进位的条件从满 10 进一变成了满 11 进一,可能导致某位数输出 10 导致错乱。输入为 95 15 时的计算过程:
先计算个位 ,c[0] = 10 ;
后计算十位 ,c[1] = 10 ;
输出从 c[max(n, m)] 即 c[2] 开始输出,有一位前导零,结果为 01010 。故选 A。
(6)前面题目的规律和证明中,规律已经水落石出。本题的限定条件中,它们的和小于 意味着最高位不产生进位,会含有前导零,且输出位数固定为 即 位。故选 C。
3.阅读以下程序:
#include <iostream>
using namespace std;
bool check_prime(int x) {
if (x <= 1) return false;
for (int i = 2; i * i <= x; i++) {
if (x % i == 0) return false;
}
return true;
}
int n;
void search_result(int x) {
if (!check_prime(x)) return;
if (x >= n) {
cout << x << endl;
return;
}
for (int i = 0; i <= 9; i++) {
search_result(x * 10 + i);
}
}
int main() {
cin >> n;
for (int i = 1; i <= 9; i++) search_result(i);
return 0;
}
(1)当输入为 10 时 程序的输出共有 10 行。( )
A.正确 B.错误
(2)若输入的 不大于 5,则程序的输出中一定包含 5。( )
A.正确 B.错误
(3)若输入的 大于 10,将第 17 行的 for (int i = 0; i <= 9; i++) 改为 for (int i = 1; i <= 9; i += 2) 后,程序的输出结果一定不变。( )
A.正确 B.错误
(4)当输入为 24 时,输出的第三行为 ( )。
A.23 B.29 C.31 D.239
(5)下列关于该程序输出的说法中,正确的是( )。
A.输出的数一定按照从小到大的顺序排列
B.随着输入 的增大,输出的行数一定不会增加
C.输出的数的个位数字只能是 3 或 7
D.输出的每个大于等于 10 的数,十进制下删去它的末位数字后得到的数一定是质数
(6)当输入为 200 时,程序输出的行数为( )。
A.12 B.13 C.14 D.15
答案:B A A B D C
解析:
程序操作解析:这是一个递归(深搜 DFS)生成“超级质数”的函数,每次在质数的基础上十进制加一位,若还是质数可以继续加(大于或等于 则输出并返回),则这些质数的前缀一定也都是质数。
(1)第一轮筛选后剩下的质数有: ;递归第二层的质数有: ,它们都大于 ,所以全部输出并返回,共 9 行而非 10 行,错误。故选 B。
(2)若 不大于 ,则 ,在第一次执行 search_result() 函数时,第一个分支判定 check_prime() 为质数而不提前返回,在第二个分支必定输出 5 。故选 A。
(3)修改后的程序少执行的 DFS 为 的偶数:
第 17 行的循环只有当本次搜索 确定为质数时执行,而质数最小是 ,则执行 search_result(x * 10 + i) 当 i 是偶数时下一层搜索内的 x 必定是合数,不会影响程序结果。故选 A。
(4)递归状态模拟:只有大于等于 24 的“超级质数”才能输出。
可见第 3 个输出的数为 。故选 B。
(5)上题推导过程中可发现,A 选项输出按从小到大并不正确;
B 选项中 的增大与输出行数有间接联系(如 时输出为 2 3 5 7 共 4 行这里省略换行; 时输出为 23 29 31 37 53 59 71 73 79 共 9 行),故 B 错误;
时输出数的个位数存在 ,而非只有 ,故 C 错误;
D 选项正确:“超级质数”的形成方式即在一个质数后面添加一个十进制位使其还是质数,当它大于等于 时删去个位必是质数。故选 D。
(6)此题纯硬算题,建议不要花过多时间在这里,算不出来就蒙中间值。
质数前缀只在 3 位数的情况输出并返回,合数永远不输出;所有输出情况为: 233 239 293 311 313 317 373 379 593 599 719 733 739 797 换行符用空格代替,共输出 14 个。故选 C。
程序设计题
选择题每题 3 分。
1.进制减半
给定 ,再给定一个 进制下的数 ,其各个数位上的数按照从高位到低位的顺序给出,请你将其转化为 进制,并同样按照从高位到低位的顺序输出。
输入的第一行依次为 和 的位数 ,接下来 个数 从高位到低位描述各个数位上的数。
数据满足 ,对于所有 。以下程序按“逐位除以 ”的方法完成进制转换。请补全程序。
#include <iostream>
constexpr int N = 100005;
long long b[N];
int main() {
long long n, m, d;
std::cin >> n >> m >> d;
int len = 1;
for (int i = 0; i < d; i++) {
long long x;
std::cin >> x;
for (int j = len; j >= 1; j--)
b[j] = ___①___;
b[0] = ___②___;
len++;
for (int j = 0; j < len; j++)
if (b[j] >= n) {
b[j + 1] += ___③___;
b[j] = ___④___;
if (j + 1 == len) len++;
}
}
while (___⑤___) len--;
for (int i = len - 1; i >= 0; i--)
std::cout << b[i] << ' ';
return 0;
}
(1)A.b[j] * n B.b[j] * m C.b[j - 1] * n D. b[j - 1] * m
(2)A.x * n B.x C. 0 D.m
(3)A.b[j] / m B.b[j] % n C.b[j] % m D.b[j] / n
(4)A.b[j] / m B.b[j] % n C.b[j] % m D.b[j] / n
(5)A.len > 0 && b[len - 1] == 0
B.len > 0 && b[0] == 0
C.len > 1 && b[len - 1] == 0
D.len > 1 && b[0] == 0
答案:D B D B C
解析:
题干已给出大致框架,一般不需要过多解释即可做题。
程序变量解释:b 数组存储当前结果的各位数字(低位在前),len 表示当前结果的长度。
(1)输入新数位前,需要把已有的结果整体乘以 。b[j] 由 b[j - 1] 乘 得到(低位到高位逐位搬运)。
(2)新输入的数位直接放在最低位,即 b[0] 。
(3)进位时,b[j] 除以 的商加到高位。
(4)进位后,b[j] 保留余数。
(5)去掉高位多余的 0,但至少保留一位(len > 1)。注意 len 是从 1 开始计数的,所以最高位是 b[len - 1] 。
2. 平衡分割
给定一个长度为 的字符串,其中每个字符都是一个十六进制数位。例如,字符串 016A 表示十进制下的四个数 。
现在请选择 个( 是你选定的数)切分位置 ,其中 ,且 。再令 ,。
对于每个 ,计算第 个数到第 个数的平均值,记作 。你的目标是使 中最大值与最小值之差尽可能小,并输出这个最小值。
其中 。输入字符串中的字符只可能是 0~9 或 A~F。本题假定字符采用 ASCII 编码。输出答案时保留小数点后 位。
以下程序通过递归枚举所有可能的连续分段方案。请补全程序。
#include <algorithm>
#include <iomanip>
#include <iostream>
using namespace std;
constexpr int N = 25;
int n, a[N];
char s[N];
double ans = 1e100;
int value(char c) { return ___①___; }
void split(int l, int cnt, double mnb, double mxb) {
if (l > n) {
if (cnt == 0) return;
ans = min(ans, mxb - mnb);
return;
}
int sum = 0;
for (___②___) {
sum += a[r];
double nwb = ___③___;
split(___④___);
}
}
int main() {
cin >> n >> s + 1;
for (int i = 1; i <= n; ++i)
a[i] = value(s[i]);
split(___⑤___);
cout << fixed << setprecision(6) << ans;
return 0;
}
(1)A.c - (c < '9' ? '0' : 'A' - 10)
B.c - (c < 'A' ? '0' : 'A' - 10)
C.c - (c < 'A' ? 'A' - 10 : '0')
D.c - (c < 'A' ? '0' : 'A' + 10)
(2)A.int r = l + 1; r <= n; ++r
B.int r = l; r < n; ++r
C.int r = l; r <= n; r += 2
D.int r = l; r <= n; ++r
(3)A.sum / (r - l + 1) * 1.0
B.sum * 1.0 / (r - l) + 1
C.sum * 1.0 / (r - l + 1)
D.(sum - a[r]) * 1.0 / (r - l + 1)
(4)A.r + 1, cnt + (r < n), min(mnb, nwb), max(mxb, nwb)
B.r + 1, cnt + (r <= n), min(mnb, nwb), max(mxb, nwb)
C.r + 1, cnt + (r < n), max(mnb, nwb), min(mxb, nwb)
D.r + 1, cnt + (r <= n), max(mnb, nwb), min(mxb, nwb)
(5)A.0, 0, 1e100, -1e100
B.0, 0, -1e100, 1e100
C.1, 0, -1e100, 1e100
D.1, 0, 1e100, -1e100
答案:B D C A D
解析:
(1)十六进制字符转数字:数字 '0' ~ '9' 减 '0',字母 'A' ~ 'F' 减 'A' - 10。判断条件是 c < 'A'。
(2)枚举当前段的右端点 r ,从 l 到 n,所以是 int r = l; r <= n; ++r 。
(3)当前段 [l, r] 的平均值 = 和 / 长度 = sum * 1.0 / (r - l + 1) 。
(4)下一层起点 r + 1,切分数 cnt + (r < n)(只有没到末尾才切一刀),更新最小值 min(mnb, nwb) ,更新最大值 max(mxb, nwb) 。
(5)初始:从位置 1 开始,切分数 0 ,最小值初始为极大值 1e100 ,最大值初始为极小值 -1e100 。
感谢阅读!码字不易,恳请帮顶!希望这篇内容对你有帮助!
广告:
Ronnie Florr.io 团队 1
Ronnie Florr.io 团队 2
最后祝大家 CSP 取得圆满成功!
全部评论 3
嗯,对我很有帮助
1周前 来自 新疆
0那太好了

1周前 来自 浙江
0再串大肆
1周前 来自 浙江
0?
1周前 来自 新疆
0
这个区 T1 选了 double,你看我就说我是区
1周前 来自 浙江
0++
1周前 来自 上海
0
T1
long long存得下吗?1周前 来自 上海
0存的下的呀
1周前 来自 浙江
0long long大概是 吧1周前 来自 浙江
0





























有帮助,赞一个