CSP-J 2026 初赛试题解析(第二部分:阅读程序题(第二题))精讲



第二题:程序(2)------大整数加法魔法工厂

大整数运算

一、为什么需要这个程序?

同学们,假设我们要计算:

复制代码
123 + 456

普通的 int 就可以完成。

但是,如果题目要求计算:

复制代码
123456789123456789123456789
+
987654321987654321987654321

普通的 int 装不下这么大的数字。


这个时候,我们就可以自己动手,使用数组来模拟加法。

这就像建立了一家魔法工厂:

  • 每个数组格子存储一位数字。

  • 从个位开始计算。

  • 每一位超过9,就向前进位。

  • 最后从最高位向最低位输出。

本程序正是利用数组实现大整数加法。试卷规定,两个非负整数的位数不超过100000,并且可能包含前导零。


二、程序的完整代码

复制代码
#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;

int main() {
    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;
}

三、先理解四个数组

程序使用了四个数组:

复制代码
int a[100007];
int b[100007];
int c[100007];
int carry[100007];

我们把它们想象成四排储物柜。

数组 作用
a 保存第一个数字的各位
b 保存第二个数字的各位
c 保存两个数字相加后的各位
carry 保存进位信息

最重要的一点是:

数组下标0保存个位,下标1保存十位,下标2保存百位......

这与我们平常从左往右写数字的习惯相反。

例如:

复制代码
输入数字:123

程序执行:

复制代码
for (int i = 0; i < a_len; i++) {
    a[i] = input_str[a_len - i - 1] - '0';
}

最终:

数组下标 0 1 2
a[i] 3 2 1
对应数位 个位 十位 百位

为什么要倒着存?

因为加法通常从个位开始计算。

倒着存储后,程序就可以从 i = 0 开始处理个位,再处理十位、百位,非常方便。


四、理解进位:个位超过9怎么办?

我们先看最简单的例子:

复制代码
  7
+ 8
---
 15

个位相加得到15。

但是,一个数位只能保存0~9,因此:

  • 当前位保存5。

  • 向高一位进1。

程序正是这样做的:

复制代码
c[i] = a[i] + b[i] + carry[i];

if (c[i] >= 10) {
    carry[i + 1] = 1;
    c[i] -= 10;
} else {
    carry[i + 1] = 0;
}

c[i] >= 10 时:

复制代码
carry[i + 1] = 1;
c[i] -= 10;

例如:

复制代码
c[i] = 15

执行后:

复制代码
c[i] = 5
carry[i+1] = 1

这就是我们熟悉的竖式加法。


五、第22题:输入123和456,输出是不是0579?

原题:

当输入为:

复制代码
123 456

程序输出为:

复制代码
0579

判断是否正确。


1. 数组初始化

输入第一个数123:

复制代码
a[0] = 3
a[1] = 2
a[2] = 1

输入第二个数456:

复制代码
b[0] = 6
b[1] = 5
b[2] = 4

初始进位:

复制代码
carry[0] = 0

2. 第0轮:计算个位

复制代码
c[0] = a[0] + b[0] + carry[0];

代入:

复制代码
c[0] = 3 + 6 + 0 = 9

9小于10,不进位:

复制代码
c[0] = 9
carry[1] = 0

3. 第1轮:计算十位

复制代码
c[1] = 2 + 5 + 0 = 7

所以:

复制代码
c[1] = 7
carry[2] = 0

4. 第2轮:计算百位

复制代码
c[2] = 1 + 4 + 0 = 5

所以:

复制代码
c[2] = 5
carry[3] = 0

5. 第3轮:多出来的一位

循环条件是:

复制代码
i < max(a_len, b_len) + 1

两个数都是3位,因此:

复制代码
i < 4

循环会执行:

复制代码
i = 0、1、2、3

第3轮时:

复制代码
a[3] = 0
b[3] = 0
carry[3] = 0

所以:

复制代码
c[3] = 0

注意,这个0并不是加法结果真正需要的数位,而是程序额外计算出来的最高位。

6. 输出

输出循环:

复制代码
for (int i = max(a_len, b_len); i >= 0; i--) {
    cout << c[i];
}

i = 3 开始输出:

复制代码
c[3] = 0
c[2] = 5
c[1] = 7
c[0] = 9

最终:

复制代码
0579

答案

√,正确。


侦探笔记

这道题有一个非常重要的细节:

程序没有删除结果最前面的0。


六、第23题:输入不含前导零,输出就一定不含前导零吗?

原题:

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


1. 什么叫前导零?

例如:

复制代码
0579

最前面的0就是前导零。

而:

复制代码
579

没有前导零。


2. 输入不含前导零,能保证输出也不含吗?

不能。

我们刚才已经计算过:

复制代码
123 + 456 = 579

但是程序输出:

复制代码
0579

因为输出循环总会从:

复制代码
max(a_len, b_len)

这个下标开始输出。

对于两个3位数来说,它会额外输出 c[3]

当没有产生最高位进位时,这一位就是0。


答案

×,错误。


侦探笔记

要区分两个概念:

  • 数学上的结果: 579。

  • 程序实际输出的字符串: 0579。

阅读程序时,不能只算数学结果,还必须严格按照输出语句执行。


七、第24题:删除进位,结果一定比原来小吗?

原题:

将第21行:

复制代码
c[i] = a[i] + b[i] + carry[i];

改为:

复制代码
c[i] = a[i] + b[i];

程序输出的结果一定比原来的结果小。


1. 进位有什么作用?

例如:

复制代码
  18
+ 27
----
  45

个位:

复制代码
8 + 7 = 15

个位留下5,向十位进1。

十位:

复制代码
1 + 2 + 1 = 4

如果把进位去掉,十位就会变成:

复制代码
1 + 2 = 3

结果就会变成35,而不是45。


2. 但是,题目说的是"一定"

我们不能只找一个会产生进位的例子。

还要考虑没有进位的情况。

例如:

复制代码
12 + 23 = 35

每一位都没有产生进位。

删除 carry[i] 后,计算结果仍然是35。

因此,修改后的输出不一定比原来小。


答案

×,错误。


侦探笔记

判断题中出现"一定""所有""必然"等词时,应该主动寻找边界情况。

没有进位的加法,就是这道题的重要反例。


八、第25题:输入12345和678,输出什么?

原题:

复制代码
12345 678

选项:

A. 012923

B. 013023

C. 13023

D. 130230


1. 先算数学结果

复制代码
  12345
+   678
-------
  13023

但不要急着选择C。

我们还要考虑程序的输出方式。


2. 观察数组长度

第一个数有5位:

复制代码
a_len = 5

第二个数有3位:

复制代码
b_len = 3

因此:

复制代码
max(a_len, b_len) = 5

程序输出循环为:

复制代码
for (int i = 5; i >= 0; i--)

它会输出:

复制代码
c[5]、c[4]、c[3]、c[2]、c[1]、c[0]

一共6位。

由于结果13023没有超过5位,因此:

复制代码
c[5] = 0

最后输出:

复制代码
013023

答案

B. 013023。


九、第26题:把 >= 10 改成 > 10,输入95和15会怎样?

原题:

将:

复制代码
if (c[i] >= 10)

改为:

复制代码
if (c[i] > 10)

当输入为:

复制代码
95 15

输出为:

A. 01010

B. 110

C. 140

D. 1410


1. 先理解修改的影响

原来的条件:

复制代码
c[i] >= 10

表示只要当前位达到10,就需要进位。

修改后:

复制代码
c[i] > 10

只有超过10才进位。

因此,恰好等于10时,程序不再进位。

这会导致错误。


2. 第0轮:个位

复制代码
5 + 5 = 10

修改后的条件:

复制代码
10 > 10

不成立。

所以:

复制代码
c[0] = 10
carry[1] = 0

注意:当前位变成了10,已经不是合法的十进制数位。


3. 第1轮:十位

复制代码
9 + 1 + 0 = 10

仍然不满足:

复制代码
10 > 10

因此:

复制代码
c[1] = 10
carry[2] = 0

4. 第2轮:额外的一位

复制代码
c[2] = 0

5. 输出

从高位到低位输出:

复制代码
c[2] = 0
c[1] = 10
c[0] = 10

注意,cout << c[i] 输出的是整数10,而不是一个字符。

所以最终字符串是:

复制代码
01010

答案

A. 01010。


侦探笔记

在进位题中:

复制代码
c[i] >= 10

和:

复制代码
c[i] > 10

差别非常大。

恰好等于10时,前者会进位,后者不会。


十、第27题:两个n位正整数相加,输出有什么特点?

原题:

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

A. 第一个字符一定不为'0'

B. 长度一定为n

C. 长度一定为n+1,且第一个字符为'0'

D. 长度可能为n+2


1. 数学结果有多少位?

题目告诉我们:

两个数都是n位正整数,并且:

复制代码
和 < 10^n

所以结果最多只有n位。

例如:

复制代码
n = 3

两个3位数相加,但结果小于1000。

那么结果可能是:

复制代码
200
999

不会超过3位。


2. 程序会输出多少位?

程序的输出循环是:

复制代码
for (int i = max(a_len, b_len); i >= 0; i--)

两个数都是n位,所以:

复制代码
max(a_len, b_len) = n

程序输出的下标是:

复制代码
n、n-1、n-2、......、1、0

一共:

复制代码
n + 1

位。


3. 最前面的字符是什么?

因为两个数的和小于 10^n,所以不会产生真正的第n+1位。

程序额外计算的:

复制代码
c[n]

就是0。

所以输出字符串一定:

  • 长度为n+1。

  • 第一个字符为'0'。


答案

C. 长度一定为n+1,且第一个字符为'0'。


第二题总结

题号 考查内容 答案
22 数组模拟加法、输出前导零
23 程序输出与数学结果的区别 ×
24 进位的重要性、反例 ×
25 数组下标、输出位数 B
26 条件边界、进位判断 A
27 循环范围、字符串长度 C

第二题通关!


相关推荐
神仙别闹1 小时前
基于 C++ 实现(控制台)关键字检索系统
c++
重生之小比特1 小时前
【初阶C++】stack和queue
开发语言·c++·vs·queue
qq_199886871 小时前
第8板块·第1节:主机与设备内存管理基础与统一内存
c++·人工智能·gpu算力·cuda
h_a_o777oah1 小时前
【图论】网络流:Dinic 算法模板实现原理及解题技巧
c++·算法·图论·acm·网络流·最小割·dinic算法
千谦阙听1 小时前
【 C++篇】:模板初阶——泛型编程、函数模板与类模板
开发语言·c++·学习·visual studio
我不会起名字3222 小时前
一天一道力扣Hot100(37):深度优先算法--括号生成
java·数据结构·c++·后端·python·算法·go
一只小小的芙厨2 小时前
CSP-J 第一轮总结
csp-j·csp·ccf
m0_734571762 小时前
深入理解C++ 多态<三>(Polymorphism)模板方法模式
开发语言·c++
Rabitebla2 小时前
【Linux 系统编程】权限(一):身份、提权,和那 9 个权限位
linux·数据结构·c++·算法