夜雨聆风学习资料网

ARTICLE · 1039335

CSP-J1_2026_试题与解析_合一版

CSP-J1_2026_试题与解析_合一版

认证时间:2026 年 9 月 19 日 09:30–11:30 满分 100 分


一、单项选择题(每题 2 分,共 30 分)

第 1 题下列 C++ 数据类型中,能够精确存储 10^18+1 这个整数的是( )。A. float B. long long C. double D. int

【答案】B【解析】 10^18+1 远超 int(约 2.1×10^9);float/double 为浮点类型,无法精确表示该整数;long long 上限约 9.2×10^18(2^63−1),可以精确存储。

第 2 题十六进制数 2F5 转换为八进制数是( )。A. 1364 B. 1635 C. 1405 D. 1365

【答案】D【解析】 0x2F5 = 2×256+15×16+5 = 757;757 = 1×8³+3×8²+6×8+5 = 1365₈。

第 3 题执行下列 C++ 代码,输出是( )。

int a = 7, b = 3;std::cout << a / b * b + a % b;

A. 9 B. 10 C. 7 D. 6

【答案】C【解析】 a/b=2(整除),2*b=6,a%b=1,输出 6+1=7。

第 4 题初始时栈为空,将 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【解析】 要第一个弹出 3,必须先入 1、2、3,此时栈中自底向上为 1、2,1 不可能在 2 之前弹出。A:入1入2弹2入3入4弹4弹3弹1;B:边入边弹;D:弹1后入2入3入4再依次弹出,均可实现。

第 5 题一棵有 100 个结点的完全二叉树,其叶子结点个数是( )。A. 49 B. 50 C. 64 D. 51

【答案】B【解析】 完全二叉树 100 个结点中,非叶子结点恰为前 ⌊100/2⌋=50 个,叶子 100−50=50。

第 6 题执行下列代码后 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【解析】 容斥:3 的倍数和 3×(1+…+33)=1683;5 的倍数和 5×(1+…+20)=1050;15 的倍数和 15×(1+…+6)=315。s=1683+1050−315=2418。陷阱项 2318 是漏算 i=100 的结果(注意循环条件是 i<=100)。

第 7 题上楼梯每步可上 1 级、2 级或 3 级,从地面(可视为第 0 级)走到第 8 级台阶共有多少种不同走法( )。A. 44 B. 121 C. 149 D. 81

【答案】D【解析】 递推 f(k)=f(k−1)+f(k−2)+f(k−3),f(0)=1, f(1)=1, f(2)=2,依次为 4,7,13,24,44,81,f(8)=81。干扰项 44=f(7)、149=f(9),都是差一级的经典错误。

第 8 题下图为 5×5 网格,行号、列号均从 0 开始,#为障碍,. 为可通行格:

     列0  列1  列2  列3  列4行0    S    .    .   #    .行1    .    .    .    .   #行2    .    .    .    .   #行3    #    #    .    E   .行4    .    .    .    .   #

从 S 出发做广度优先搜索(BFS):初始时把 S 入队;每次取出队首格子,按"上、下、左、右"(上=行号减 1,下=行号加 1,左=列号减 1,右=列号加 1)的顺序遍历它的四个相邻格子,越界、障碍或已访问的格子跳过,其余格子标记为已访问并入队。当 E 第一次入队时,已经入队过的格子(含 S 和 E)共有多少个( )。A. 15 B. 12 C. 14 D. 13

【答案】C【解析】 按规则逐层模拟(入队即标记已访问):

入队格子
累计
0
(0,0)
1
1
(1,0), (0,1)
3
2
(2,0), (1,1), (0,2)
6
3
(2,1), (1,2)
8
4
(2,2), (1,3)
10
5
(3,2), (2,3)
12
6
(4,2) → E(3,3)
14

处理 (3,2) 时按 U/D/L/R 顺序:上已访问、下 (4,2) 入队(第 13 个)、左是障碍、右 E 入队(第 14 个)。(3,4)、(4,0)~(4,3) 等都在 E 之后才入队,不计入。手模拟最容易在层数上错一格,从 14 错成 13 或 15。

第 9 题满足 1 ≤ n ≤ 100 且 gcd(n, 60) = 6 的正整数 n 共有多少个( )。A. 8 B. 6 C. 4 D. 5

【答案】B【解析】 n 必为 6 的倍数:n=6k,gcd(6k,60)=6·gcd(k,10)=6 ⟺ gcd(k,10)=1,即 k 为奇数且非 5 的倍数:k∈{1,3,7,9,11,13}(6×17>100),对应 n=6,18,42,54,66,78,共 6 个。

第 10 题某国硬币面值为 1 元、4 元、6 元且数量不限,凑出 9 元最少需要多少枚( )。A. 3 B. 4 C. 5 D. 2

【答案】A【解析】 9=4+4+1,3 枚即可;2 枚无法凑出 9(6+3、4+5 均不行)。

第 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[0]=5,p[2]=9,故 (p−1)=a[1]=5+9=14;随后 p[1]=a[3]=(a+1)−a[0]=a[1]−a[0]=14−1=13。注意第二句用的是已经更新后的 a[1]=14。输出 "14,13"。

第 12 题在含 1000 个互不相同元素的升序数组中,用二分法查找给定值(返回元素位置或报告不存在),最坏情况下需要与数组元素比较多少次( )。A. 500 B. 9 C. 11 D. 10

【答案】D【解析】 最坏比较次数 = ⌈log₂(1001)⌉ = 10。

第 13 题数组 a[1..n] 的前缀和数组 s(即 s[i]=a[1]+a[2]+…+a[i])满足 s[i] = 3i²+i。则 a[10] 的值是( )。A. 252 B. 310 C. 58 D. 61

【答案】C【解析】a[10]=s[10]−s[9]=(3×100+10)−(3×81+9)=310−252=58

第 14 题数轴上有 7 个点,坐标分别为 1、3、4、7、10、15、20。在数轴上选取一个整数坐标点 P,使 P 到这 7 个点的距离之和最小,这个最小距离和是( )。A. 37 B. 42 C. 40 D. 38

【答案】A【解析】 距离和在 P 取中位数(第 4 个点,坐标 7)时最小:6+4+3+0+3+8+13=37。

第 15 题一个无向图有 10 个顶点,其中 4 个顶点的度为 3,其余顶点的度均为 4,则该图的边数是( )。A. 36 B. 18 C. 17 D. 20

【答案】B【解析】 握手定理:边数=(4×3+6×4)/2=36/2=18。


二、阅读程序(判断题 1.5 分/题,选择题 3 分/题,第 16 题 1 分,共 40 分)

程序(1)

#includeusing namespace std;intmain() {    int n;    cin >> n;    int x = 1, y = 1;    while (n > 0) {              // 第 7 行        if (n % 2 == 0) {            ++x;        } else {            ++x;                 // 第 11 行            ++y;        }        n = n / 2;    }    cout << x << ” ” << y << endl;    return 0;}

第 16 题(判断,1 分) 当输入为 3 时,程序输出为 3 3。( )

【答案】√【解析】 n=3(二进制 11):两次迭代均为奇数,两个分支都有 ++x,故 x=1+2=3;else 分支各有一次 ++y,y=1+2=3。输出"3 3"。

第 17 题(判断) 将第 11 行的 ++x; 删除后,程序输出的两个数一定相等。( )

【答案】×【解析】 删除后 else 分支只剩 ++y:x=1+偶数商的个数,y=1+二进制中 1 的个数,两者一般不等。反例 n=3:x=1,y=3。

第 18 题(判断) 假设输入为非负整数,则程序输出的第一个数一定不小于第二个数。( )

【答案】√【解析】 每个迭代分支都有 ++x,故 x=1+二进制位长;y=1+二进制中 1 的个数。位长 ≥ 1 的个数恒成立(n=0 时输出 1 1,取等号)。

第 19 题(选择) 将第 7 行的 while (n > 0) 改为 while (n >= 0) 后,程序可能出现的问题是( )。

A. 陷入死循环 B. 输出结果比原来大 C. 输出结果比原来小 D. 输出结果不受影响

【答案】A【解析】 n>=0 时,0/2 恒为 0,n 永远是 0,循环条件恒真,陷入死循环。

第 20 题(选择) 当输入为 6 时,输出为( )。

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

【答案】C【解析】 n=6(110):迭代 3 次,x=1+3=4;奇数商为 3、1 共 2 个,y=1+2=3。输出"4 3"。

第 21 题(选择) 若输入 n 依次取遍 0, 1, 2, …, 2^31−1 中的所有整数,则程序输出的第二个数恰好为 2 的次数为( )。

A. 16 B. 30 C. 31 D. 32

【答案】C【解析】 第二个数 y=2 ⟺ y=1+popcount(n)=2 ⟺ popcount(n)=1 ⟺ n 是 2 的幂。02^31−1 中 2^02^30 共 31 个(2^31 超出输入范围,勿多算)。

程序(2)(大整数加法)

#include#include#includeusing namespace std;int a[100007], b[100007], c[100007], carry[100007];string input_str;int a_len, b_len;intmain(){    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];              // 第 21 行        if (c[i] >= 10) {                           // 第 22 行            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;}

第 22 题(判断) 当输入为 123 456 时,程序输出为 0579。( )

【答案】√【解析】 123+456=579;输出循环从 i=max=3 开始,c[3]=0 被先输出,结果为"0579"。

第 23 题(判断) 假设输入的两个数均不含前导零,则程序输出的结果也一定不含有前导零。( )

【答案】×【解析】 只要没有产生最终进位,最高位 c[max]=0 也会被输出——结果必带前导零(如 22 题的 0579)。

第 24 题(判断) 将第 21 行改为 c[i] = a[i] + b[i]; 后,程序输出的结果一定比原来的结果小。( )

【答案】×【解析】 反例 55+55:原输出 110;改后各位不再进位,c[1]=c[0]=10,输出"01010"(数值 1010 > 110),反而更大。

第 25 题(选择) 当输入为 12345 678 时,输出为( )。

A. 012923 B. 013023 C. 13023 D. 130230

【答案】B【解析】 12345+678=13023;max(a_len,b_len)=5,c[5]=0 打头,输出"013023"。

第 26 题(选择) 将第 22 行的 if (c[i] >= 10) 改为 if (c[i] > 10) 后,当输入为 95 15 时,输出为( )。

A. 01010 B. 110 C. 140 D. 1410

【答案】A【解析】 改为 >10 后,和为 10 不再进位:个位 5+5=10、十位 9+1=10 都不进位,c[0]=c[1]=10、c[2]=0,从高位输出"01010"。

第 27 题(选择) 假设输入的两个数均为 n 位正整数(不含前导零),且它们的和小于 10^n,则程序输出的字符串一定满足( )。

A. 第一个字符一定不为 '0'                       B. 长度一定为 n

C. 长度一定为 n+1,且第一个字符为 '0'   D. 长度可能为 n+2

【答案】C【解析】 两个 n 位数之和 ≥10^(n−1) 且 <10^n,是 n 位数,无最终进位:c[n]=0 被输出打头,总长 n+1,首字符必为 '0'。

程序(3)(可接长质数搜索)

#includeusing namespace std;boolcheck_prime(int x) {    if (x <= 1return false;    for (int i = 2; i * i <= x; i++) {        if (x % i == 0return false;    }    return true;}int n;voidsearch_result(int x) {    if (!check_prime(x)) return;    if (x >= n) {        cout << x << endl;        return;                 // 输出后不再向右扩展    }    for (int i = 0; i <= 9; i++) {              // 第 17 行        search_result(x * 10 + i);    }}intmain() {    cin >> n;    for (int i = 1; i <= 9; i++)        search_result(i);    return 0;}

第 28 题(判断) 当输入为 10 时,程序的输出共有 10 行。( )

【答案】×【解析】 n=10 时输出 23、29、31、37、53、59、71、73、79,共 9 行。注意 31 很容易被漏数。

第 29 题(判断) 若输入的 n 不大于 5,则程序的输出中一定包含 5。( )

【答案】√【解析】 main 从 1~9 起搜,5 是质数;n≤5 时 5≥n,搜索到 5 时必然直接输出。

第 30 题(判断) 若输入的 n 大于 10,将第 17 行的 for (int i = 0; i <= 9; i++) 改为 for (int i = 1; i <= 9; i += 2) 后,程序的输出结果一定不变。( )

【答案】√【解析】 末位为偶数的扩展数(大于 2)必为合数,本来就会在 check_prime 处被剪掉;删去偶数 i 不影响任何输出。

第 31 题(选择) 当输入为 24 时,程序输出的第 3 行为( )。

A. 23 B. 29 C. 31 D. 239

【答案】B【解析】 深度优先顺序:2→23→233(≥24 输出)→239(输出);回到 29(≥24 输出)。前 3 行:233、239、29

第 32 题(选择) 下列关于该程序输出的说法中,正确的是( )。

A. 输出的数一定按照从小到大的顺序排列

B. 随着输入 n 的增大,输出的行数一定不会增加

C. 输出的数的个位数字只可能是 3 或 7

D. 输出的每个大于等于 10 的数,十进制下删去它的末位数字后得到的数一定是质数

【答案】D【解析】 每个输出的数都处在"前缀全为质数"的搜索路径上,删去末位即其前缀,必为质数。A 错(DFS 序非全局升序);B 错(n 增大行数会增加);C 错(个位可为 1、9 等,如 311、719)。

第 33 题(选择) 当输入为 200 时,程序输出的行数为( )。

A. 12 B. 13 C. 14 D. 15

【答案】C【解析】 ≥200 的可接长质数共 14 个:2 支 233、239、293;3 支 311、313、317、373、379;5 支 593、599;7 支 719、733、739、797。注意 613、673 等不会出现——前缀 61、67 的前缀 6 不是质数,从单位数出发根本到不了。本题是全卷"时间黑洞",建议熟悉右接长质数(可截断质数)或按分支逐位硬判。


三、完善程序(每题 3 分,共 30 分)

(1)进制转换

给定 n, m,再给定一个 m·n 进制下的数 A,其各个数位上的数按照从高位到低位的顺序给出,请你将其转化为 n 进制,并按照从高位到低位的顺序输出。输入的第一行依次为 n, m 和 A 的位数 d,接下来 d 个数从高位到低位描述各个数位。数据满足 2 ≤ n, m ≤ 10,1 ≤ d ≤ 18,0 ≤ A < 2^63。

以下程序按"逐位除以 n"的方法完成进制转换。请补全程序。

#includeconstexpr int N = 100005;long long b[N];intmain(){    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;}

第 34 题① 处应填( )。

A. b[j] * n B. b[j] * m C. b[j - 1] * n D. b[j - 1] * m

【答案】D【解析】 b 数组低位在前表示 n 进制数。读入新数位 x 后 b ← b×(m·n)+x:乘 n 等价于整体右移一位(b[j]←b[j−1] 由循环从高到低完成),每位再乘 m 完成乘 m·n。故 ① 填 b[j−1]*m。

第 35 题② 处应填( )。A. x * n B. x C. 0 D. m

【答案】B【解析】 新读入的数位落在最低位 b[0]=x。

第 36 题③ 处应填( )。

A. b[j] / m B. b[j] % n C. b[j] % m D. b[j] / n

【答案】D【解析】 归一化(进位):高位 b[j+1] 加上 b[j] 除以 n 的商。

第 37 题④ 处应填( )。A. b[j] / m B. b[j] % n C. b[j] % m D. b[j] / n

【答案】B【解析】 当前位保留除以 n 的余数。

第 38 题⑤ 处应填( )。

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

【答案】C【解析】 去掉高位多余的零;len>1 保证至少保留一位(A=0 时不会把数组删空)。b[0] 是最低位,与本题无关。

(2)平衡分割

给定一个长度为 n 的字符串,其中每个字符都是一个十六进制数位(如 016A 表示 0,1,6,10)。选择 k 个切分位置把字符串分成 k+1 段,使各段平均值中最大值与最小值之差尽可能小,输出这个最小值(保留 6 位小数)。其中 2 ≤ n ≤ 20,字符只可能是 09 或 AF。以下程序通过递归枚举所有可能的连续分段方案。请补全程序。

#include#include#includeusing namespace std;constexpr int N = 25;int n, a[N];char s[N];double ans = 1e100;intvalue(char c)return ①; }voidsplit(int l, int cnt, double mxb, double mnb){    if (l > n) {        if (cnt == 0return;        ans = min(ans, mxb - mnb);        return;    }    int sum = 0;    for (②) {        sum += a[i];        double nwb = ③;        split(④);    }}intmain(){    cin >> n >> s + 1;    for (int i = 1; i <= n; ++i)        a[i] = value(s[i]);    split(⑤);    cout << fixed << setprecision(6) << ans;    return 0;}

第 39 题① 处应填( )。

A. isdigit(c) ? c - '0' : c - 'A' + 10

B. c <= '9' ? c - '0' : c - 'A' + 10

C. c - 'A' + 10

D. c - '0'

【答案】B【解析】 A 是陷阱:isdigit 需要头文件,程序并未包含,严格编译下不可用;B 用纯字符比较,对保证合法的 0–9/A–F 输入完全正确。C、D 各只覆盖一半字符。

第 40 题② 处循环头应填( )。

A. int i = 0; i < n; i++

B. int i = 1; i < n; i++

C. int i = 0; i <= n; i++

D. int i = l; i <= n; i++

【答案】D【解析】 段的右端点 i 必须从当前位置 l 枚举到 n(数组 1 起始)。A、C 从 0 开始会读到 a[0] 垃圾值;B 起点错且 i<n 漏掉末元素。

第 41 题③ 处(求当前段平均值)应填( )。

A. (double)sum                 B. sum / (i - l + 1) 

C. (double)sum / (i - l + 1) D. 1.0 * sum / i

【答案】C【解析】 必须强制双精度除法,且段长为 i−l+1。B 是整数除法(如 5/2=2)必错;D 段长错。

第 42 题④ 处(递归调用参数)应填( )。

A. i+1, cnt+1, max(mxb, nwb), min(mnb, nwb)

B. i, cnt+1, max(mxb, nwb), min(mnb, nwb)

C. i+1, cnt, max(mxb, nwb), min(mnb, nwb)

D. i, cnt, max(mxb, nwb), min(mnb, nwb)

【答案】A【解析】 下一段从 i+1 开始(B、D 填 i 会让 a[i] 被下一段重复计入);每形成一段 cnt 加 1(C 漏加);同时用新段平均值更新最大(mxb)和最小(mnb)。

第 43 题⑤ 处(main 中初始调用 split 的参数)应填( )。

A. 1, 0, 0, 0 

B. 0, 1, 1e100, 1e100 

C. 1, 1, 0, 0 

D. 1, 0, -1e100, 1e100

【答案】D【解析】 起点 l=1(1 起始数组)。注意形参顺序是 (l, cnt, mxbmnb):第三形参 mxb 初值取 −1e100,一路 max 上来成为最大平均值;第四形参 mnb 初值取 +1e100,一路 min 下来成为最小平均值;递归到底时 mxb−mnb 即该分段方案的"最大−最小",再用 ans 取全局最小。A、C 的 0 初值会把最小值永远卡在 0;B 的 l=0 直接错位。


答案速览

部分
题号
答案
单项选择
1–15
B D C C B D D C B A A D C A B
阅读程序(1)
16–21
√ × √ A C C
阅读程序(2)
22–27
√ × × B A C
阅读程序(3)
28–33
× √ √ B D C
完善程序(1)
34–38
D B D B C
完善程序(2)
39–43
B D C A D

相关学习资料