夜雨聆风学习资料网

ARTICLE · 1054459

2026年CSP-J第一轮试题详解(中):阅读程序

2026年CSP-J第一轮试题详解(中):阅读程序
2026年CSP-J第一轮试卷共43题,分为单项选择、阅读程序和完善程序三个部分。为便于阅读,本次解析分为上、中、下三篇。
本篇为中篇,集中解析第16至33题。三段程序分别涉及二进制统计、高精度加法和深度优先搜索。

备注:依据两份完整试卷独立整理,对照AKCSP、OIerMaster、CSDN和OneCoder等多方资料逐题交叉核验。程序输出、边界条件及争议题另按原卷代码独立推演,力求最大限度减少误差。 

截至发文,CCF/NOI尚未公布正式标准答案,最终以官方发布为准。

本篇答案速查

16-21  √ × √ A C C22-27  √ × × B A C28-33  × √ √ B D C

第16至21题:除以2的程序在统计什么

第一段程序读入n,令x=y=1,然后不断执行n=n/2。每轮x都会加1,只有当前n为奇数时y才加1。

因此,对正整数来说,x=二进制位数+1y=二进制中1的个数+1。先抓住这两个含义,六道题就不必逐句猜。

程序代码

#include<iostream>using namespace std;intmain(){    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;}

第16题

当输入为3时,程序输出为3 3。( )

答案

正确

解读

输入3时,二进制是11,循环两轮,两轮都是奇数,最后x=3、y=3


第17题

将奇数分支中的++x;删除后,程序输出的两个数一定相等。( )

答案

错误

解读

删除奇数分支里的++x后,x只在遇到二进制位0时增加,y只在遇到1时增加,两者当然不一定相等。例如输入1,最终就是1 2


第18题

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

答案

正确

解读

原程序每轮都让x加1,而y只在部分轮次加1,两者初值又相同,所以始终有x≥y


第19题

while (n > 0)改为while (n >= 0)后,程序可能出现的问题是( )。

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

答案

A

解读

若条件改成n>=0,当n变为0后,0/2仍是0,循环条件永远成立,程序陷入死循环。


第20题

当输入为6时,输出为( )。

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

答案

C

解读

4 36的二进制是110,共3位、含2个1,因此输出“位数+1、1的个数+1”,即4 3


第21题

若输入n依次取遍0,1,2,...,2^31-1,程序输出的第二个数恰好为2的次数是( )。

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

答案

C

解读

31次。第二个数等于2,意味着二进制中恰好有一个1,也就是2的非负整数次幂。在02^31-1中,有2^02^30,共31个。


第22至27题:高精度加法故意多输出一位

第二段程序把两个十进制整数倒序存入数组,逐位相加并处理进位。算法主体并不陌生,真正的陷阱在输出:它总是从下标max(a_len,b_len)打印到0,因此固定输出“最大位数+1”位。没有最高位进位时,开头就会多一个0。

程序代码

#include<algorithm>#include<iostream>#include<string>using 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];        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];    cout << endl;    return 0;}

题目说明:两个输入均为非负整数,位数不超过100000,可能包含前导零。

第22题

当输入为123 456时,程序输出为0579。( )

答案

正确

解读

123+456=579,程序固定输出4位,所以结果是0579


第23题

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

答案

错误

解读

即使两个输入都没有前导零,只要相加后没有产生新的最高位,程序仍会打印数组中多出来的那个0。


第24题

c[i]=a[i]+b[i]+carry[i];改为c[i]=a[i]+b[i];后,程序输出的结果一定比原来的结果小。( )

答案

错误

解读

删除carry[i]会漏掉进位,但结果不一定“严格小于”原结果。比如1+1没有进位,两种写法输出完全相同。


第25题

当输入为12345 678时,输出为( )。

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

答案

B

解读

01302312345+678=13023,最大输入长度是5,程序会打印6位,所以前面补出一个0。


第26题

将判断条件c[i]>=10改为c[i]>10后,当输入为95 15时,输出为( )。

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

答案

A

解读

01010。把>=10误改为>10后,恰好等于10的某一位不会进位,也不会减10。输入95和15时,两位的c[i]都可能直接保存整数10;cout不会限制每个数组元素只打印一位,最终拼成0、10、10,即01010


第27题

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

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

答案

C

解读

两个n位数的和小于10^n,说明没有新增最高位。程序仍固定打印n+1个位置,所以长度是n+1,首字符为0


这组题提醒我们:分析程序输出,不能擅自把代码“修正”为正常写法。程序有没有去掉前导零、一个数组元素会不会打印成两位,都要忠实于现有代码。

第28至33题:DFS输出的不是排序结果

第三段程序从1至9依次出发。当前数不是质数就立即返回;若它已经不小于输入的n,就输出并停止向后添加数字;否则依次在末尾添加0至9,继续深度优先搜索。

所以,输出的是一批“从右侧不断删去末位后,沿途仍为质数”的数。程序采用深度优先搜索,先一路向更深处走,再回头尝试下一个分支,输出顺序不等于数值从小到大。

程序代码

#include<iostream>using 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++)        search_result(x * 10 + i);}intmain(){    cin >> n;    for (int i = 1; i <= 9; i++)        search_result(i);    return 0;}

第28题

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

答案

错误

解读

输入10时,输出23、29、31、37、53、59、71、73、79,一共9行,不是10行。


第29题

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

答案

正确

解读

n≤5时,主程序调用search_result(5),5是质数且已经满足5≥n,因此一定会输出5。


第30题

若输入的n大于10,将循环改为for (int i=1;i<=9;i+=2)后,程序的输出结果一定不变。( )

答案

正确

解读

n>10时,继续扩展的是多位质数。多位质数的末位不可能是偶数或5,因此只尝试1、3、5、7、9不会漏掉原本能够通过质数检查的分支。


第31题

当输入为24时,程序输出的第3行是( )。

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

答案

B

解读

第3行是29。输入24后,搜索先从23继续向下,依次输出233、239,回溯后才输出29。因此前三行是233、239、29,不能按大小排序想成23、29、31。


第32题

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

  • A. 输出的数一定从小到大排列
  • B. 随着输入n增大,输出行数一定不会增加
  • C. 输出数的个位只可能是3或7
  • D. 输出的每个不小于10的数,删去十进制末位后得到的数一定是质数

答案

D

解读

每个被输出的多位数都来自某个已经通过质数检查的前缀,所以删去最后一位后,得到的数一定是质数。A错在DFS并非升序;B错在阈值增大后可能继续搜索出更多后代;C错在个位也可能是1或9。


第33题

当输入为200时,程序输出的行数为( )。

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

答案

C

解读

14行。输入200时可按首位分支统计:从2出发有233、239、293共3个;从3出发有311、313、317、373、379共5个;从5出发有593、599共2个;从7出发有719、733、739、797共4个,总数3+5+2+4=14


小结

三段程序最典型的陷阱分别是初值多出的1、高精度程序固定多打印一位,以及DFS输出顺序并非数值升序。看懂功能只是第一步,把边界和输出顺序算到底才是得分点。下一篇将详解两段完善程序。

相关学习资料