题解:洛谷 P1303 A B Problem
【题目来源】
洛谷:P1303 A*B Problem - 洛谷(luogu.com.cn)
【题目描述】
给出两个非负整数,求它们的乘积。
【输入】
输入共两行,每行一个非负整数。
【输出】
输出一个非负整数表示乘积。
【输入样例】
1
2
【输出样例】
2
【核心思想】
-
问题分析:计算两个非负大整数的乘积,长度可达 \(10^5\) 位(甚至更大)。需要实现高精度乘法,模拟手算竖式乘法的过程。本质是大整数乘法,通过逐位相乘并累加进位来实现。
-
算法选择:
- 竖式模拟:将两个数按字符串读入,逆序存入数组(个位在
[0])。对每一位相乘,将结果累加到对应的位置[i+j],然后处理进位。最后去除前导零。 - 时间复杂度:\(O(la \times lb)\),其中 \(la, lb\) 是位数。对于长度较大的数(如 \(10^5\)),此方法不可行,需使用 FFT/NTT 等快速算法,但本题数据范围较小(原题未明确,通常适合 \(10^3\) 级别),竖式模拟足够。
- 竖式模拟:将两个数按字符串读入,逆序存入数组(个位在
-
关键步骤(以第二个代码版本为例):
- 读入与逆序存储:将字符串
a和b逆序存入A和B,个位在索引0。 - 逐位相乘:双重循环
i从0到la-1,j从0到lb-1:C[i+j] += A[i] * B[j]C[i+j+1] += C[i+j] / 10C[i+j] %= 10
- 去除前导零:结果数组
C的长度为lc = la + lb,从高位向低位找到第一个非零位。 - 输出:逆序输出
C的有效位。
- 读入与逆序存储:将字符串
-
时间/空间复杂度:
- 时间复杂度:\(O(la \times lb)\)。
- 空间复杂度:\(O(la + lb)\)。
-
高精度乘法模拟:
- 逆序存储:与加法类似,个位在索引
0便于进位。 - 进位处理:每次累加后,立即处理进位,确保
C[i]始终保持为个位数。 - 前导零:乘积可能为 0,需确保输出至少一个
0。 - 适用场景:高精度乘法是算法竞赛的基础内容,用于处理超大整数运算。
- 逆序存储:与加法类似,个位在索引
【算法标签】
普及- #高精度
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int c[2005] = {0}; // 用于存储乘法结果的每一位数字
// 高精度乘法函数:计算两个大整数的乘积
int amulb(string a, string b)
{
int j1[2005] = {0}, j2[2005] = {0}; // j1 和 j2 用于存储两个大整数的每一位数字
int lena = a.length(), lenb = b.length(); // lena 和 lenb 分别表示两个大整数的长度
int len = lena + lenb; // len 表示乘法结果的最大可能位数
// 将字符串 a 和 b 转换为 int 数组并翻转(方便从低位到高位计算)
for (int i = 0; i < lena; i++) j1[lena - i] = a[i] - '0'; // 将 a 的每一位字符转换为数字并翻转
for (int i = 0; i < lenb; i++) j2[lenb - i] = b[i] - '0'; // 将 b 的每一位字符转换为数字并翻转
// 逐位相乘
for (int i = 1; i <= lena; i++)
{
for (int j = 1; j <= lenb; j++)
{
c[i + j - 1] += j1[i] * j2[j]; // 当前位的乘积累加到 c[i+j-1]
c[i + j] += c[i + j - 1] / 10; // 处理进位
c[i + j - 1] %= 10; // 当前位只保留个位数
}
}
// 去除结果前导的 0
while (c[len] == 0 && len > 1)
len--;
return len; // 返回结果的位数
}
int main() {
string a, b; // 用于存储输入的两个大整数
int n; // 用于存储乘法结果的位数
cin >> a >> b; // 输入两个大整数
// 调用高精度乘法函数,计算 a * b 的结果
n = amulb(a, b);
// 输出结果(从高位到低位)
for (int i = n; i >= 1; i--)
cout << c[i];
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 100005; // 数组大小,足够大
int A[N], B[N], C[N]; // 存储大数的数组
int la, lb, lc; // 数组A、B、C的实际长度
string a, b; // 输入的大数字符串
// 高精度乘法函数
void mul(int A[], int B[], int C[])
{
// 双重循环,模拟竖式乘法
for (int i = 0; i < la; i++)
{
for (int j = 0; j < lb; j++)
{
C[i + j] += A[i] * B[j]; // 累加乘积
C[i + j + 1] += C[i + j] / 10; // 进位
C[i + j] %= 10; // 保留个位
}
}
// 处理前导零
while (lc > 0 && C[lc] == 0)
{
lc--; // 去除最高位的0
}
}
int main()
{
// 输入两个大数
cin >> a >> b;
// 计算长度
la = a.size();
lb = b.size();
lc = la + lb; // 乘积的最大可能位数是两数位数之和
// 将字符串逆序存储到数组中
// 注意:这里存储方式是个位在A[0](与之前代码不同)
for (int i = la - 1; i >= 0; i--)
{
A[la - 1 - i] = a[i] - '0'; // 个位在A[0]
}
for (int i = lb - 1; i >= 0; i--)
{
B[lb - 1 - i] = b[i] - '0'; // 个位在B[0]
}
// 执行高精度乘法
mul(A, B, C);
// 输出结果
for (int i = lc; i >= 0; i--)
{
cout << C[i];
}
return 0;
}
【运行结果】
12
4
48
浙公网安备 33010602011771号