【题目原文引自 CCF 2026 CSP-J1 真题卷,解析为本站原创整理】 全文 43 题的题干、选项均已对照真题卷原文核验;答案与分步解析为个人整理结果,最终以 CCF 官方公布为准。

真题卷完整扫描页见本站《2026 CSP-J 第一轮认证真题卷》。https://noi.hnai.net/csp/460.html

一、参考答案速查表

题号 答案 题号 答案 题号 答案
1 B 12 D 23 ×
2 D 13 C 24 ×
3 C 14 A 25 B
4 C 15 B 26 A
5 B 16 27 C
6 D 17 × 28 ×
7 D 18 29
8 C 19 A 30
9 B 20 C 31 B
10 A 21 C 32 D
11 A 22 33 C
34 D 35 B 36 D
37 B 38 C 39 A
40 A 41 A 42 B
43 A

分段小结:

单选 B D C C B D D C B A A D C A B

阅读程序(1) √ × √ A C C;(2) √ × × B A C;(3) × √ √ B D C

完善程序(1) D B D B C;(2) A A A B A


二、单项选择题(共 15 题,每题 2 分,共计 30 分)

第 1 题

下列 C++ 数据类型中,能够精确存储 10¹⁸ + 1 这个整数的是( )

A. float B. long long C. double D. int

参考答案:B

分步解析:10¹⁸ + 1 = 1000000000000000001,是一个 19 位十进制整数。

  • int:32 位,上限 2147483647(10 位),装不下;
  • float:32 位单精度,有效数字仅约 7 位;
  • double:64 位双精度,有效数字约 15~16 位,存 19 位数会丢精度;
  • long long:64 位有符号整数,上限约 9.22×10¹⁸,10¹⁸ + 1 可精确存储。

考点:C++ 数据类型范围与精度。

第 2 题

十六进制数 2F5 转换为八进制数是( )

A. 1364 B. 1635 C. 1405 D. 1365

参考答案:D

分步解析

  1. 十六进制转十进制:2F5₁₆ = 2×256 + 15×16 + 5 = 512 + 240 + 5 = 757;
  2. 十进制转八进制(除 8 取余):757÷8=94 余 5,94÷8=11 余 6,11÷8=1 余 3,1÷8=0 余 1;
  3. 逆序排列得 1365₈(验算:1×512+3×64+6×8+5 = 757 ✓)。

考点:进制转换。

第 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 = 7 / 3 = 2a / b * b = 2 * 3 = 6a % b = 1;6 + 1 = 7。选 A 的同学是把 a/b*b 当成了 a(还原成 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

分步解析

  • A:1入、2入、2出;3入、4入、4出、3出、1出 → 合法;
  • B:每次「入一个出一个」→ 合法;
  • C:第一个出 3,说明 1、2、3 已在栈中,此时栈顶是 2,下一个却要出 1 → 非法
  • D:1入1出;2、3、4 依次入,再 4、3、2 依次出 → 合法。

考点:栈的入栈/出栈序列合法性。

第 5 题

一棵有 100 个结点的完全二叉树,其中叶子结点个数是( )

A. 49 B. 50 C. 64 D. 51

参考答案:B

分步解析:编号从 1 起,最后一个非叶子结点是 ⌊100/2⌋ = 50 号;叶子结点为 51~100 号,共 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+6+…+99 = 1683)+ 5 的倍数和(5+10+…+100 = 1050)− 15 的倍数和(15+30+…+90 = 315)= 1683 + 1050 − 315 = 2418

考点:容斥原理、循环累加。

第 7 题

上楼梯每步可上 1 级、2 级或 3 级,从地面(可视为第 0 级)走到第 8 级台阶共有多少种不同走法( )

A. 44 B. 121 C. 149 D. 81

参考答案:D

分步解析:设 f(i) 为走到第 i 级的走法数,则 f(i) = f(i−1) + f(i−2) + f(i−3),f(0)=1,f(1)=1,f(2)=2 → 4、7、13、24、44、81。注意选项 A 的 44 是第 7 级,属于「少递推一步」的陷阱。

考点:递推(三阶斐波那契类)。

第 8 题

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

S . . # .
. . . # .
. . . # .
# # . . E
. . . # .

从 S 出发做广度优先搜索(BFS):初始时把 S 入队;每次取出队首格子,按「上、下、左、右」的顺序遍历四个相邻格子,越界、障碍或已访问的跳过,其余标记为已访问并入队。当 E 第一次入队时,已经入队过的格子(含 S 和 E)共有多少个( )

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

参考答案:C

分步解析:按队列顺序逐个登记(序号即入队次序):

  1. (0,0)=S 2. (1,0) 3. (0,1) 4. (2,0) 5. (1,1) 6. (0,2)
  2. (2,1) 8. (1,2) 9. (2,2) 10. (3,2) 11. (4,2) 12. (3,3) 13. (4,1) 14. (3,4)=E

关键在 2~3 行中间那一列 # 把路卡住,只能从 (2,2) 向下钻到 (3,2) 再展开。建议一格一格写队列,凭感觉数极易数成 13 或 15。

考点:BFS 的队列模拟。

第 9 题

满足 1 ≤ n ≤ 100 且 gcd(n, 60) = 6 的正整数 n 共有多少个( )

A. 8 B. 6 C. 4 D. 5

参考答案:B

分步解析:设 n = 6t,则 gcd(n, 60) = 6·gcd(t, 10),要等于 6 就必须 gcd(t, 10) = 1(t 既不是 2 的倍数也不是 5 的倍数)。又 n ≤ 100 → t ≤ 16。

t ∈ {1, 3, 7, 9, 11, 13} → n ∈ {6, 18, 42, 54, 66, 78},共 6 个。

网上有解析只算出 4 个,是把条件误当成 gcd(t, 60) = 1,漏掉了 t = 3、t = 9。

考点:最大公约数、互质计数。

第 10 题

某国硬币面值为 1 元、4 元、6 元且数量不限,凑出 9 元最少需要多少枚( )

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

参考答案:A

分步解析:枚举可行组合——6+1+1+1 = 4 枚;4+4+1 = 3 枚;4+1×5 = 6 枚;1×9 = 9 枚。最少 3 枚。注意这不是简单的贪心题,凑不出 9−6=3 所以不能先取 6。

考点:枚举/完全背包思想。

第 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 指向 a[2]=5。

  • *(p−1) = p[0] + p[2] → a[1] = a[2] + a[4] = 5 + 9 = 14(a[1] 被改写);
  • p[1] = *(a+1) − a[0] → a[3] = a[1] − a[0] = 14 − 1 = 13(注意此时 a[1] 已是 14,不是 3);
  • 输出 14,13

考点:指针运算、指针与数组的关系。

第 12 题

在含 1000 个互不相同元素的升序数组中,用二分法查找给定值,最坏情况下需要与数组元素比较多少次?( )

A. 500 B. 9 C. 11 D. 10

参考答案:D

分步解析:二分查找最坏比较次数 = ⌈log₂(n+1)⌉ = ⌈log₂1001⌉;2⁹ = 512 < 1001 ≤ 1024 = 2¹⁰ → 10 次。

考点:二分查找的时间复杂度。

第 13 题

数组 a[1..n] 的前缀和数组 s(即 s[i] = a[1] + … + a[i])满足 s[i] = 3i² + i。则 a[10] 的值是( )

A. 252 B. 310 C. 58 D. 61

参考答案:C

分步解析:由差分 a[i] = s[i] − s[i−1] → a[10] = s[10] − s[9] = (3×100 + 10) − (3×81 + 9) = 310 − 252 = 58。选项 A(252)就是 s[9]、选项 B(310)就是 s[10],都是给忘了差分这一步的同学准备的。

考点:前缀和与差分。

第 14 题

数轴上有 7 个点,坐标分别为 1、3、4、7、10、15、20。在数轴上取一个整数坐标点 P,使 P 到这 7 个点的距离之和最小,这个最小距离和是( )

A. 37 B. 42 C. 40 D. 38

参考答案:A

分步解析:绝对距离和最小的点取中位数,7 个点的中位数是第 4 个 = 7。以 P = 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 = 12 + 24 = 36;无向图边数 = 度数和 ÷ 2 = 18。选项 A 就是「忘记除以 2」的结果。

考点:握手定理。


三、阅读程序(共 40 分)

程序(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;   // 第 11 行
            ++y;
        }
        n = n / 2;
    }
    cout << x << ' ' << y << endl;
    return 0;
}

程序功能:循环把 n 除以 2。x = 循环次数 + 1 = 二进制位数 + 1;y = 遇到的奇数次数 + 1 = 二进制中 1 的个数 + 1。看懂这两个计数器的含义,本组 6 题就都通了。

16.(1 分)当输入为 3 时,程序输出为 3 3。( )→ √

3 = 11₂:n=3 奇 → x=2, y=2, n=1;n=1 奇 → x=3, y=3, n=0 → 输出 3 3

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

删掉后偶数只加 x、奇数只加 y,两者不再同步。取 n = 1:只走奇数分支 → x = 1、y = 2,输出 1 2 不相等。

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

x 统计总位数 + 1,y 统计 1 的个数 + 1,1 的个数不可能超过总位数,故 x ≥ y 恒成立。

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

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

n = 0 时原循环不进入;改成 >= 0 后进入,走偶数分支 ++x,而 n = 0/2 仍是 0,永远不满足 n < 0 → 死循环。

20. 当输入为 6 时,输出为( )→ C

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

6 = 110₂:n=6 偶 → x=2, n=3;n=3 奇 → x=3, y=2, n=1;n=1 奇 → x=4, y=3 → 4 3

21. 若输入 n 依次取遍 0,1,…,2³¹−1,则输出第二个数恰好为 2 的次数为( )→ C

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

y = 2 ⟺ 二进制中恰有 1 个 1 ⟺ n 是 2 的幂。0 ~ 2³¹−1 中是 2⁰…2³⁰ 共 31 个(别把 2³¹ 算进去,它已超出范围)。

程序(2):高精度加法

int a[100007], b[100007], c[100007], carry[100007];
// 读入两个字符串,倒序存入 a[]、b[](低位在前)
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];

程序功能:非负整数高精度加法。抓手:输出固定为 max(a 位数, b 位数) + 1 位,因此高位经常出现前导零——本组 6 题全部围绕这一点设问。

22. 当输入为 123 456 时,程序输出为 0579。( )→ √

123 + 456 = 579,循环到 3+1 = 4 位,c[3] = 0 → 逆序输出 0579

23. 假设输入的两个数均不含前导零,则输出也一定不会含有前导零。( )→ ×

只要两数位数相同且最高位无进位就会产生前导零,例如 111 + 222 = 333,输出 0333

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

丢掉进位后,等于 10 的位不再减 10 进位。例如 5 + 5:原程序输出 10,改后 c[0] = 10,输出 010数值相等而非更小。

25. 当输入为 12345 678 时,输出为( )→ B

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

12345 + 678 = 13023,共 6 位,最高位补 0 → 013023

26. 将第 22 行 if (c[i]>=10) 改为 if (c[i]>10) 后,输入 95 15 时输出为( )→ A

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

个位 5+5 = 10、十位 9+1 = 10,都不满足 >10,于是不进位也不减 10:c[0] = 10、c[1] = 10、c[2] = 0 → 输出 0 10 10 拼成 01010。这题考的是「你是否真的理解判断条件在干什么」。

27. 输入两个数均为 n 位正整数(无前导零),和小于 10ⁿ,则输出字符串一定满足( )→ C

A. 第一个字符一定不为 ‘0’ B. 长度一定为 n C. 长度一定为 n+1,且第一个字符为 ‘0’ D. 长度可能为 n+2

和 < 10ⁿ 说明最高位没有进位,c[n] = 0,而循环固定走到 n+1 位 → 长度 n+1、首字符为 0

程序(3):右截断素数 DFS

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++)            // 第 17 行
        search_result(x * 10 + i);
}
int main() {
    cin >> n;
    for (int i = 1; i <= 9; i++) search_result(i);
    return 0;
}

程序功能:从 1~9 出发,每次在末尾追加一位数字,要求每一步得到的数都必须是质数;一旦 ≥ n 就输出并停止深入。这类数称为右截断素数。注意输出顺序是 DFS 搜索序,不是从小到大。

28. 当输入为 10 时,程序的输出共有 10 行。( )→ ×

n = 10 时输出 23、29、31、37、53、59、71、73、79 共 9 行。

29. 若输入的 n 不大于 5,则程序的输出中一定包含 5。( )→ √

5 本身是质数且 5 ≥ n,一定被输出。

30. 若 n 大于 10,将第 17 行改为 for (int i=1;i<=9;i+=2) 后,输出结果一定不变。( )→ √

n > 10 时输出的都大于 10,而大于 10 的质数个位只能是 1、3、7、9(偶数或 5 结尾必被整除),追加偶数/5 分支永远产生不了新答案,故结果不变。

31. 当输入为 24 时,程序输出的第 3 行为( )→ B

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

搜索顺序:从 2 出发 → 23(< 24,继续)→ 233、239(第 1、2 行)→ 回到 2 的最后一个分支 29(≥ 24,第 3 行)。所以第 3 行是 29,不是按大小排的 31。

32. 下列关于该程序输出的说法中,正确的是( )→ D

A. 输出的数一定按从小到大排列(错:DFS 序,如 233、239、29) B. 随着 n 增大输出行数一定不会增加(错) C. 输出数的个位只可能是 3 或 7(错:还可能是 1、9,如 31、59) D. 输出的每个 ≥ 10 的数,删去末位后一定是质数(对:这是右截断素数的定义)

33. 当输入为 200 时,程序输出的行数为( )→ C

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

输出的是三位右截断素数,共 14 个:233、239、293、311、313、317、373、379、593、599、719、733、739、797。这是全卷最费时的一题——要么熟悉这类数的规律,要么把每个两位质数再往后接一位逐个判质数。


四、完善程序(单选题,每小题 3 分,共计 30 分)

程序(1):mn 进制转 n 进制(34–38)

题意:给定 n、m,再给定一个 mn 进制下的数 A(数位从高位到低位给出),把它转化为 n 进制并按同样顺序输出。程序采用「逐位处理」的方法:每读入一位 x,就把已有结果整体后移一位(等价于 ×n)并乘以 m,再加上 x,最后统一进位。

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--;

34. ①处应填( )→ D A. b[j]*n B. b[j]*m C. b[j-1]*n D. b[j-1]*m

数组在 n 进制下存储,下标整体 +1 就是 ×n,再乘 m 即 b[j-1]*m

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

新读入的一位直接放进个位。

36. ③处应填( )→ D A. b[j]/m B. b[j]%n C. b[j]%m D. b[j]/n

进位时把商加到高位。

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

当前位保留模 n 的余数。

38. ⑤处应填( )→ C 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

去掉高位前导零,但 len > 1 保证至少保留一位(结果可能就是 0)。

程序(2):平衡分割(39–43)

题意:给定长度为 n 的字符串,每个字符都是一个十六进制数位(例如 016A 表示 0、1、6、10)。选 k 个切分位置把它分成 k+1 段(1 ≤ k < n),计算每段的平均值 b₀…bₖ,目标是让这些平均值的最大值与最小值之差尽可能小,输出该最小值(保留 6 位小数)。2 ≤ n ≤ 20,字符只可能是 0~9 或 A~F。

int get_val(char c) { return ①; }
void split(int l, int cnt, double minb, double maxb) {
    if (l > n) {
        if (cnt == 0) return;
        ans = min(ans, maxb - minb);
        return;
    }
    int sum = 0;
    for (②) {
        sum += ③;
        double nwb = ④;
        split(⑤);
    }
}
int main() {
    cin >> n >> s + 1;
    split(1, -1, 1e100, -1e100);
    cout << fixed << setprecision(6) << ans;
}

39. ①处应填( )→ A

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

字符可能是 A~F,必须按十六进制换算:’A’ 应得到 10。B 会得到 0,C 把数字整体 +1,D 得到 9,都不对。

40. ②处应填( )→ A

A. int r = l; r <= n; r++ B. int r = l; r < n; r++ C. int r = 1; r <= n; r++ D. int r = l; r++ < n

段末位置 r 必须能取到 n,否则最后一段无法收尾、递归终点 l > n 永远达不到,ans 不会被更新。B、D 都停在 n−1;C 每次从 1 开始,段就乱了。

41. ③处应填( )→ A

A. get_val(s[r]) B. get_val(s[r-1]) C. s[r-1] D. s[r]

配合 ② 的 r 从 l 到 n,累加当前字符的数值。B 首轮会取到上一段末尾的 s[l−1];C、D 直接加 ASCII 码——题干那句「假定字符采用 ASCII 编码」正是给这两个选项准备的烟雾弹。

42. ④处应填( )→ B

A. sum/(r-l+1) B. 1.0*sum/(r-l+1) C. 1.0*sum/(r-l) D. sum*1.0/n

平均值是小数(输出保留 6 位),必须用浮点除法;A 的整数除法会截断。C 分母少 1,D 分母用 n 不对。

43. ⑤处应填( )→ A

A. r+1, cnt+1, min(minb,nwb), max(maxb,nwb) B. r, cnt+1, minb, maxb C. r+1, cnt, nwb, nwb D. r, cnt, min(minb,nwb), max(maxb,nwb)

下一段从 r+1 开始;cnt 记录段数 − 1(初值 −1),每分出一段就 +1,终态 cnt == 0 表示一刀没切(只有 1 段),按题意 k ≥ 1 舍去;同时更新已见平均值的最小/最大值。

⚠️ 重要更正:网传解析给出的 39–43 答案(如 B D C A D)与卷面原文不符,多半是按想象中的空白位置作答。本文已对照原卷逐空验证,正确答案为 A A A B A


五、写在最后

2026 年这套 J 组初赛知识点不偏、计算量偏大:纯记忆性的计算机常识题一道没有,全部是算法与数学类;区分度主要来自细心程度。

建议复盘时重点盯三类题目——需要手工模拟的(第 8 题 BFS)、需要理解输出格式的(高精度前导零)、需要理清搜索顺序的(右截断素数 DFS);另外 39–43 的平衡分割是本卷审查最密集的部分,值得把程序整体重写一遍。

预祝各位同学初赛取得好成绩,复赛再见!