ARTICLE · 1054414
2026年CSP-J第一轮试题详解(下):完善程序
本篇为下篇,集中解析第34至43题,并进行整卷复盘。两段程序分别涉及进制转换和平衡分割。
备注:依据两份完整试卷独立整理,对照AKCSP、OIerMaster、CSDN和OneCoder等多方资料逐题交叉核验。程序输出、边界条件及争议题另按原卷代码独立推演,力求最大限度减少误差。
截至发文,CCF/NOI尚未公布正式标准答案,最终以官方发布为准。
本篇答案速查
34-38 D B D B C39-43 B D C A D
第34至38题:把“进制减半”看成乘法与进位
第一段完善程序要把一个m×n进制数转成n进制。数组b按从低位到高位保存当前结果。每读入一个新数位x,新的整体数值都满足:
新值 = 旧值 × (m×n) + x而在n进制中,乘以m×n可以理解为先乘以n,也就是整体向高位移动一位,再把各位乘以m,随后统一处理超过n-1的数位。
题目与程序: 给定n、m和一个m×n进制数A。A的各数位按从高到低给出,要求把它转换成n进制,并同样从高位到低位输出。数据满足2≤n,m≤10、位数1≤d≤18、0≤A<2^63,每个原数位均在0到m×n-1之间。
程序代码
#include<iostream>constexpr 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] * nB. b[j] * mC. b[j-1] * nD. b[j-1] * m
答案
D
解读
b[j - 1] * m。原来的第j-1位移到第j位,同时乘以m。
第35题
②处应填( )。
A. x * nB. xC. 0D. m
答案
B
解读
x。新读入的数位直接放到最低位b[0],之后再由后面的循环处理可能产生的进位。
第36题
③处应填( )。
A. b[j] / mB. b[j] % nC. b[j] % mD. b[j] / n
答案
D
解读
b[j] / n。当前位超过范围时,除以n得到的商应累加到更高一位。
第37题
④处应填( )。
A. b[j] / mB. b[j] % nC. b[j] % mD. b[j] / n
答案
B
解读
b[j] % n。进位之后,当前位只保留除以n的余数。
第38题
⑤处应填( )。
A. len > 0 && b[len-1] == 0B. len > 0 && b[0] == 0C. len > 1 && b[len-1] == 0D. len > 1 && b[0] == 0
答案
C
解读
len > 1 && b[len - 1] == 0。输出前删掉最高位的前导零,但必须至少保留一位,否则数值0会被删成空输出。
这五个空不是五道互不相关的语法题。34、35完成“乘基数再加新位”,36、37完成n进制进位,38负责规范输出。把整体数值变化写出来,比逐个试选项稳得多。
第39至43题:本卷最需要警惕网传答案的一组
“平衡分割”把十六进制字符串看成一列数,例如016A对应0、1、6、10。程序枚举所有连续分段方案,计算每一段的平均值,希望让各段平均值中的最大值与最小值之差尽量小。
这里既有字符转换,也有区间平均值、递归边界和极值初值。网上有一份解析把这五题列成A、A、A、B、A,但它与原卷选项及另外四个来源不一致。按原程序逐空检查,应为B、D、C、A、D。
题目与程序: 给定长度为n的十六进制数位字符串,在相邻字符之间选择至少一个切分位置。每一段计算数值平均值,目标是让所有段平均值中的最大值与最小值之差尽可能小。2≤n≤20,字符只可能为0至9或A至F。
程序代码
#include<algorithm>#include<iomanip>#include<iostream>using 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 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(④);}}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. 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)
答案
B
解读
对'0'至'9'应减'0',对'A'至'F'应减'A'-10,所以条件是c<'A'。选项A使用c<'9',会把字符'9'误判到字母分支。
第40题
②处应填( )。
A. int r=l+1; r<=n; ++rB. int r=l; r<n; ++rC. int r=l; r<=n; r+=2D. int r=l; r<=n; ++r
答案
D
解读
int r=l; r<=n; ++r。当前连续段可以只有一个元素,因此右端点从l开始;它也可以一直延伸到最后一个元素,因此必须枚举到n。
第41题
③处应填( )。
A. sum / (r-l+1) * 1.0B. sum * 1.0 / (r-l) + 1C. sum * 1.0 / (r-l+1)D. (sum-a[r]) * 1.0 / (r-l+1)
答案
C
解读
sum*1.0/(r-l+1)。区间[l,r]包含r-l+1个数;乘1.0是为了进行浮点除法。选项A先做整数除法,再乘1.0,小数部分已经丢失。
第42题
④处应填( )。
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)
答案
A
解读
当前段结束于r,下一段从r+1开始;只有r<n时才真的在后面切了一刀,所以计数增加(r<n);同时用当前平均值更新最小值和最大值。
第43题
⑤处应填( )。
A. 0, 0, 1e100, -1e100B. 0, 0, -1e100, 1e100C. 1, 0, -1e100, 1e100D. 1, 0, 1e100, -1e100
答案
D
解读
split(1,0,1e100,-1e100)。字符串下标从1开始,初始尚未切分;最小平均值先设成极大的正数,最大平均值先设成极小的负数,第一次更新才能自然得到当前段的平均值。
这组题最难的并不是某一个表达式,而是要同时理解四个状态:下一段从哪里开始、做了几次切分、目前最小平均值是多少、目前最大平均值是多少。画出一次递归调用的参数变化,会比盯着选项反复比较更清楚。
怎样用这张卷子复盘
如果只是把答案改对,这份试卷的价值只用了一小部分。更有效的做法,是把错题按原因分开:
概念不准:如第1题的精度、第15题的度数和,需要回到定义。 计算不稳:如进制、容斥、递推、前缀和,要把中间过程写全。 代码没有逐行执行:如第11、26、31题,适合画变量表、数组表或递归树。 忽略限定词:如第8题的“第一次入队”、第27题的“和小于 10^n”。只记答案没还原算法:如两段完善程序,应先用一句话说明每个变量和整个程序的目标,再看空格。
如果孩子准备第二轮,复盘到“知道自己为什么错”就可以及时转向上机。数组与字符串处理、模拟、排序查找、递推和基础搜索,仍然需要通过完整写程序来巩固。
小结
完善程序不能把五个空拆成五道孤立语法题。先写出程序目标和关键状态,再检查移位、进位、递归边界与极值初值,答案会稳定得多。第39至43题经原卷和四个来源核对,应为B、D、C、A、D。