夜雨聆风学习资料网

ARTICLE · 1054414

2026年CSP-J第一轮试题详解(下):完善程序

2026年CSP-J第一轮试题详解(下):完善程序
2026年CSP-J第一轮试卷共43题,分为单项选择、阅读程序和完善程序三个部分。为便于阅读,本次解析分为上、中、下三篇。

本篇为下篇,集中解析第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≤180≤A<2^63,每个原数位均在0m×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] * n
  • B. b[j] * m
  • C. b[j-1] * n
  • D. b[j-1] * m

答案

D

解读

b[j - 1] * m。原来的第j-1位移到第j位,同时乘以m


第35题

②处应填( )。

  • A. x * n
  • B. x
  • C. 0
  • D. m

答案

B

解读

x。新读入的数位直接放到最低位b[0],之后再由后面的循环处理可能产生的进位。


第36题

③处应填( )。

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

答案

D

解读

b[j] / n。当前位超过范围时,除以n得到的商应累加到更高一位。


第37题

④处应填( )。

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

答案

B

解读

b[j] % n。进位之后,当前位只保留除以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 && 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,字符只可能为09AF

程序代码

#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 == 0return;        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; ++r
  • B. int r=l; r<n; ++r
  • C. int r=l; r<=n; r+=2
  • D. int r=l; r<=n; ++r

答案

D

解读

int r=l; r<=n; ++r。当前连续段可以只有一个元素,因此右端点从l开始;它也可以一直延伸到最后一个元素,因此必须枚举到n


第41题

③处应填( )。

  • 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)

答案

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, -1e100
  • B. 0, 0, -1e100, 1e100
  • C. 1, 0, -1e100, 1e100
  • D. 1, 0, 1e100, -1e100

答案

D

解读

split(1,0,1e100,-1e100)。字符串下标从1开始,初始尚未切分;最小平均值先设成极大的正数,最大平均值先设成极小的负数,第一次更新才能自然得到当前段的平均值。


这组题最难的并不是某一个表达式,而是要同时理解四个状态:下一段从哪里开始、做了几次切分、目前最小平均值是多少、目前最大平均值是多少。画出一次递归调用的参数变化,会比盯着选项反复比较更清楚。

怎样用这张卷子复盘

如果只是把答案改对,这份试卷的价值只用了一小部分。更有效的做法,是把错题按原因分开:

  1. 概念不准:如第1题的精度、第15题的度数和,需要回到定义。
  2. 计算不稳:如进制、容斥、递推、前缀和,要把中间过程写全。
  3. 代码没有逐行执行:如第11、26、31题,适合画变量表、数组表或递归树。
  4. 忽略限定词:如第8题的“第一次入队”、第27题的“和小于10^n”。
  5. 只记答案没还原算法:如两段完善程序,应先用一句话说明每个变量和整个程序的目标,再看空格。

如果孩子准备第二轮,复盘到“知道自己为什么错”就可以及时转向上机。数组与字符串处理、模拟、排序查找、递推和基础搜索,仍然需要通过完整写程序来巩固。

小结

完善程序不能把五个空拆成五道孤立语法题。先写出程序目标和关键状态,再检查移位、进位、递归边界与极值初值,答案会稳定得多。第39至43题经原卷和四个来源核对,应为B、D、C、A、D。

相关学习资料