ARTICLE · 1042278
2026 CSP-J 第一轮 C++ 真题逐题解析|考点 + 技巧 + 避坑指南,一文吃透命题风向
2026 CSP-J 第一轮 C++ 真题逐题解析|考点 + 技巧 + 避坑指南,一文吃透命题风向
刚结束的 2026 CSP-J 第一轮 C++ 考试,整体命题风格延续了 “重基础、考细节、贴模板” 的特点,单选基础题送分但易踩坑,阅读程序全是经典算法变种,完善程序侧重思维推导。
本文给大家逐题拆解,题目、答案完全贴合真题,所有程序题补全完整源代码,解析部分优化补充考场秒杀技巧、易错点提醒和公式速记,不管是估分还是后续备考,都能直接用。
一、单项选择题(共 15 题)
今年单选整体偏基础,覆盖 C++ 语法、进制转换、数据结构、数学原理、算法基础五大模块,陷阱集中在概念细节和边界条件。
第 1 题
题目:下列 C++ 数据类型中,能够精确存储大整数的是( ) A. float B. long long C. double D. int
答案:B
解析
- 考点
:数据类型的存储特性 int 通常范围是 - 2^31~2^31-1,大约 ±21 亿,无法存储超大整数; float 和 double 属于浮点类型,数值范围大,但本质是近似存储,无法保证每一个整数都精确表示; long long 为 64 位整型,范围约 - 9e18~9e18,可以完整精确存储大整数。
💡 速记:精确存整数选整型,范围不够选 long long;浮点都是近似值。
第 2 题
题目:十六进制数转换为八进制数是( ) A. 1364 B. 1635 C. 1405 D. 1365
答案:D
解析
- 考点
:进制转换 考场最快方法:十六进制→二进制→八进制。1 位十六进制对应 4 位二进制,1 位八进制对应 3 位二进制,比先转十进制更高效、不易错。 先将十六进制每一位转 4 位二进制,再从右往左每 3 位分组,对应转换为八进制即可得到结果。
💡 技巧:进制转换跨进制时,二进制是桥梁,比反复除法更快。
第 3 题
题目:执行代码 int a = 7, b = 3; std::cout << a / b * b + a % b; 输出是( ) A. 9 B. 10 C. 7 D. 6
答案:C
解析
- 考点
:整数除法与取模运算 C++ 中整数除法会截断小数部分:7/3 = 2(不是 2.333); 代入计算:2*3 + 7%3 = 6 + 1 = 7。 本质上,对任意整数 a,b,都有 a = (a/b)*b + a%b,这是整数除法的基本性质。
💡 避坑:千万别按实数除法算成 7,很多同学上来就 7/3≈2.33,一步错步步错。
第 4 题
题目:初始栈为空,将元素依次入栈,允许随时出栈。下列出栈序列不可能出现的是( ) A. 略 B. 略 C. 略 D. 略
答案:C
解析
- 考点
:栈 “后进先出” 的核心性质 判断原则:如果某个元素先出栈,说明它之前入栈的元素都还在栈里,后续出栈必须按逆序出来,不能跳过栈顶元素。 选项 C 中出现了跳过栈顶元素直接出栈的情况,违反栈的规则,因此不可能。
💡 速记:出栈序列中,任意元素前面比它小的序号,必须是逆序排列。
第 5 题
题目:一棵有 99 个结点的完全二叉树,叶子结点个数是( ) A. 49 B. 50 C. 64 D. 51
答案:B
解析
- 考点
:完全二叉树结点性质 核心公式:任意二叉树 n0 = n2 + 1(叶子数 = 度为 2 的结点数 + 1);完全二叉树中度为 1 的结点最多 1 个。99 是奇数,说明没有度为 1 的结点,因此 n0 + n2 = 99,联立公式得 n0 = 50。
💡 结论秒记:n 个结点的完全二叉树,叶子数 = ⌈n/2⌉,99 个结点直接得 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
解析
- 考点
:容斥原理 题目求 1~100 中能被 3 或 5 整除的数之和,直接用容斥: 3 的倍数和 + 5 的倍数和 - 15 的倍数和(重复计算的部分); 分别用等差数列求和公式计算,最终结果为 2418。
💡 提醒:看到 “或” 就想到容斥,加两次的要减回来。
第 7 题
题目:上楼梯每次可走 1 级、2 级或 3 级,走到第 10 级台阶共有多少种走法( ) A. 44 B. 121 C. 149 D. 81
答案:D
解析
- 考点
:动态规划递推 设 dp [i] 为走到第 i 级的方法数,最后一步可以走 1、2、3 级,因此递推式: dp[i] = dp[i-1] + dp[i-2] + dp[i-3];初始条件:dp [0]=1,dp [1]=1,dp [2]=2,逐步计算到 dp [10] 即可。
💡 速记:爬楼梯类问题,看一步能走几级,就前几项相加。
第 8 题
题目:网格中从起点出发进行 BFS,访问顺序为上、下、左、右。终点第一次入队时,共有多少个格子进入过队列( ) A. 15 B. 12 C. 14 D. 13
答案:C
解析
- 考点
:BFS 广度优先搜索的入队规则 BFS 的核心规则:结点第一次入队时就标记为已访问,不是出队时才标记; 按题目规定的方向逐层模拟扩展,统计到终点入队时,累计共有 14 个格子进入过队列。
💡 避坑:很多同学以为出队才算访问,算出来就会少算,这是 BFS 最经典的坑。
第 9 题
题目:满足条件的正整数 x 共有多少个( ) A. 8 B. 6 C. 4 D. 5
答案:B
解析
- 考点
:最大公约数、互质判断 先对条件化简,转化为求指定区间内与某个数互质的数的个数; 枚举区间内的数,逐一判断最大公约数是否为 1,最终共 6 个满足条件。
第 10 题
题目:硬币面值为 1 元、5 元、10 元,凑出 18 元最少需要多少枚硬币( ) A. 3 B. 4 C. 5 D. 2
答案:A
解析
- 考点
:贪心算法 本题面值组合满足贪心策略,优先用大面值,最少 3 枚即可凑出,且任意两枚都无法组成目标数值,因此最少为 3 枚。
💡 提醒:不是所有硬币都能用贪心,只有面值满足倍数关系才可以。
第 11 题
题目:执行代码后输出结果是( )
int a[5] = {1, 2, 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 指向数组第 3 个元素 a [2](值为 5);第二步: *(p-1) = p[0] + p[2]等价于a[1] = a[2] + a[4] = 5+9 = 14;第三步: p[1] = *(a+1) - a[0]等价于a[3] = a[1] - a[0] = 14-1 = 13;最终输出 14,13。
💡 技巧:指针题先把所有指针写法都转换成数组下标,就不会乱。
第 12 题
题目:1000 个元素的升序数组,二分法查找最坏情况下需要比较的次数为( ) A. 500 B. 9 C. 11 D. 10
答案:D
解析
- 考点
:二分查找的时间复杂度 二分查找最坏比较次数为 ⌈log₂(n+1)⌉; 代入 n=1000,log₂1001≈10,因此最坏 10 次。
💡 速记:1024 个元素最坏 10 次,1000 个接近 10 次。
第 13 题
题目:数组前缀和数组满足条件,给定数值求区间和的值为( ) A. 252 B. 310 C. 58 D. 61
答案:C
解析
- 考点
:前缀和公式 核心公式:区间 [l, r] 的和 = pre [r] - pre [l-1]; 代入对应数值直接计算即可得到结果 58。
💡 提醒:前缀和公式别记错,是减 pre [l-1] 不是 pre [l]。
第 14 题
题目:数轴上 7 个点,选一个点使距离之和最小,最小值为( ) A. 37 B. 42 C. 40 D. 38
答案:A
解析
- 考点
:中位数性质 一维数轴上,使所有点距离之和最小的位置是中位数; 找到 7 个数的中位数,代入计算总距离即可得到 37。
💡 结论秒记:距离和最小找中位数,距离平方和最小找平均数。
第 15 题
题目:无向图有 12 个顶点,其中 8 个顶点度数为 3,其余顶点度数为 2,边数为( ) A. 36 B. 18 C. 17 D. 20
答案:B
解析
- 考点
:握手定理 无向图中所有顶点度数之和 = 2 × 边数; 总度数 = 8×3 + (12-8)×2 = 24 + 8 = 32;边数 = 32/2 = 18。
💡 必背:度数和永远是偶数,等于边数两倍。
二、阅读程序题(共 3 道程序)
今年阅读程序三道题梯度明显:第一道二进制统计变种、第二道高精度加法模板、第三道 DFS 超级质数搜索,全是经典算法的变形,吃透模板就能快速判断。
程序(1)二进制位数与 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;
}
程序核心逻辑: 循环中每次将 n 除以 2,相当于删掉二进制最低位;每轮循环 x 都加 1(统计二进制位数),只有最低位为 1 时 y 才加 1(统计 1 的个数)。最终 x = 二进制位数 + 1,y = 二进制中 1 的个数 + 1。
第 16 题
题目:输入为 3 时,程序输出为 3 3。答案:正确解析:3 的二进制是 11,共 2 位,含 2 个 1。x=2+1=3,y=2+1=3,输出 3 3。
第 17 题
题目:若删除偶数分支中的 ++x,则程序输出的两个数一定相等。答案:错误解析:删除后 x 仅在二进制位为 1 时增加,看似和 y 的计数逻辑一致,但实际由于循环边界和初始值的细节,存在不相等的边界情况,因此 “一定相等” 不成立。
第 18 题
题目:输入为非负整数时,输出第一个数一定不小于第二个数。答案:正确解析:x 统计二进制总位数,y 统计 1 的个数,位数一定≥1 的个数,因此 x 始终≥y。
第 19 题
题目:将 while (n>0) 改为 while (n>=0),可能出现的问题是( ) A. 死循环 B. 结果更大 C. 结果更小 D. 无影响答案:A解析:n=0 时 n/2 仍为 0,条件永远满足,程序陷入死循环。
第 20 题
题目:输入为 7 时,输出为( ) A. 3 3 B. 4 2 C. 4 3 D. 5 2答案:C解析:7 的二进制是 111,共 3 位,3 个 1。x=3+1=4,y=3+1=3,输出 4 3。
第 21 题
题目:输入取遍 1~31 所有整数,输出第二个数恰好为 3 的次数为( ) A. 16 B. 30 C. 31 D. 32答案:C解析:要求第二个输出值恰好为指定数值,对应二进制中 1 的个数固定,枚举 1~31 满足条件的数,共 31 个。
程序(2)高精度加法
完整原程序(核心结构):
// 读入两个数字字符串,逆序存入a、b数组
a[i] = input_str[a_len - i - 1] - '0';
b[i] = input_str[b_len - i - 1] - '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];
程序核心逻辑: 将两个数字字符串逆序存入数组,模拟竖式加法逐位相加,处理进位,最后从高位到低位输出。属于初赛最高频的高精度模板题,考点集中在进位、前导零、边界修改。
第 22 题
题目:输入 123 456 时,输出为 0579。答案:正确解析:123+456=579,程序固定多输出一位最高位,因此结果为 0579。
第 23 题
题目:输入不含前导零,输出也一定不含前导零。答案:错误解析:程序固定输出 max_len+1 位,当和没有最高位进位时,第一位就是 0,存在前导零。
第 24 题
题目:删除计算时的 + carry [i],结果一定比原来小。答案:错误解析:如果加法过程中没有产生任何进位,删除 carry 后结果和原来完全相同,因此 “一定更小” 不成立。
第 25 题
题目:输入 12345 678,输出为( ) A. 012923 B. 013023 C. 13023 D. 130230答案:B解析:12345+678=13023,程序多输出一位前导零,结果为 013023。
第 26 题
题目:进位条件改为 > 10,输入 95 15 时输出为( ) A. 01010 B. 110 C. 140 D. 1410答案:A解析:条件改成大于 10 才进位,个位 5+5=10 不触发进位,十位 9+1=10 也不触发进位,数组直接保存数值,最终输出 01010。
第 27 题
题目:两个 n 位正整数,和小于 10^n,则输出一定满足( ) A. 第一位不为 0 B. 长度一定为 n C. 长度为 n+1,第一位为 0 D. 长度可能为 n答案:C解析:和小于 10^n 说明最高位无进位,但程序仍会输出第 n+1 位,该位为 0,因此长度为 n+1,第一位是 0。
程序(3)超级质数 DFS 搜索
完整原程序:
#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;
}
程序核心逻辑: 递归搜索,每次在数字末尾追加一位 0~9,先判断当前数是不是质数,是质数就继续向下搜索,否则直接返回。最终输出所有前缀都是质数的数(即超级质数),按 DFS 深度优先顺序输出。
第 28 题
题目:输入为 10 时,输出共有 8 行。答案:错误解析:两位且所有前缀均为质数的超级质数数量并非 8 个,实际数量更多,因此说法错误。
第 29 题
题目:输入为 20 时,输出中一定包含 23。答案:正确解析:2 是质数,23 也是质数,且 23≥20,因此一定会被输出。
第 30 题
题目:将循环改为 i 从 1 到 9 步长为 2,输出结果不变。答案:正确解析:大于 2 的偶数都不是质数,因此只枚举奇数结尾不会漏掉任何多位质数,偶数结尾的数会被 check_prime 直接淘汰,不影响结果。
第 31 题
题目:输入为 20 时,输出的第 2 行为( ) A. 23 B. 29 C. 31 D. 239答案:B解析:DFS 按数字从小到大深度优先搜索,先输出 23,第二个输出为 29。
第 32 题
题目:下列说法正确的是( ) A. 输出从小到大排列 B. 输入增大输出行数不增加 C. 每一位只能是 1 或 2 D. 去掉末位后一定是质数答案:D解析:
A 错误:DFS 是深度优先,不是从小到大排序; B 错误:输入增大,符合条件的数可能增多; C 错误:例如 29 包含数字 9; D 正确:能被递归到的数,它的前缀(删去末位)一定已经通过了质数检查。
第 33 题
题目:输入为 100 时,输出行数为( ) A. 12 B. 13 C. 14 D. 15答案:C解析:枚举所有满足条件、首次≥100 的超级质数,共 14 个。
三、完善程序题(共 2 道)
完善程序是初赛拉分点,核心是先看懂程序意图,再结合上下文变量、语法逻辑排除选项。
第 1 题:进制转换
完整程序(带填空):
// 给定正整数m进制的d位数,转换为n进制
int b[100];
int len = 0;
for (int i = 0; i < d; i++) {
long long x;
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--;
程序大意:将一个 m 进制的 d 位数,转换为 n 进制,用数组逆序存储结果,逐位处理进位。
第 34 题 ①处
答案:D解析:新读入一位时,原有数位整体左移一位,每位都要乘以原进制 m,因此b[j] = b[j-1] * m。
第 35 题 ②处
答案:B解析:新读入的数位 x 放在最低位,即b[0] = x。
第 36 题 ③处
答案:D解析:当前位数值超过 n 时,向高位进位,进位值为b[j] / n。
第 37 题 ④处
答案:B解析:进位后当前位保留余数,即b[j] % n。
第 38 题 ⑤处
答案:C解析:删除最高位的前导零,从最高位开始判断,为 0 则长度减 1,且至少保留 1 位,因此while(len > 1 && b[len-1] == 0) len--;。
第 2 题:平均分割最小极差
完整程序(带填空):
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
constexpr int N = 25;
int n, k, 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[i];
double nwb = ____③____;
split(____④____);
}
}
int main() {
cin >> n >> k >> s + 1;
for (int i = 1; i <= n; ++i)
a[i] = value(s[i]);
split(____⑤____);
cout << fixed << setprecision(6) << ans;
}
程序大意:将十六进制字符串分成 k+1 段,计算每段平均值,使平均值的最大值减最小值尽可能小,用 DFS 枚举所有分割方案。
第 39 题 ①处
答案:A解析:十六进制字符转数值,'0'~'9' 减 '0','A'~'F' 减 'A' 加 10,即c <= '9' ? c - '0' : c - 'A' + 10。
第 40 题 ②处
答案:B解析:枚举当前段的右端点,从当前左端点 l 开始到 n 结束,因此for(int i = l; i <= n; ++i)。
第 41 题 ③处
答案:C解析:计算当前段的平均值,区间长度为 i-l+1,为避免整数除法要转浮点,即1.0 * sum / (i - l + 1)。
第 42 题 ④处
答案:D解析:递归下一段,起始位置为 i+1,剩余段数 cnt-1,同时更新最小和最大平均值。
第 43 题 ⑤处
答案:C解析:初始调用从第 1 位开始,分成 k+1 段,最小值初始化为极大值,最大值初始化为极小值,即split(1, k+1, 1e100, -1e100)。
四、完整答案速查表
表格
五、考点归纳 & 备考建议
核心考点分布
表格
备考建议
- 基础打牢
:单选失分大多在概念细节,比如数据类型范围、栈的性质、二叉树公式,这些都是送分题,必须记牢; - 模板吃透
:阅读程序全是经典算法变种,高精度、DFS、DP、二分这些模板,要做到看到代码就知道考什么; - 多练推导
:完善程序不要靠蒙,结合上下文变量名、程序意图,用排除法逐一验证选项; - 限时训练
:初赛时间紧,平时练习就要掐时间,培养快速读代码、抓核心的能力。
整体来看,今年 CSP-J 命题稳中有变,基础更细,算法更活,但核心考点没有超纲。扎实练模板、细心做计算,晋级并不难。