目录
大整数乘法
要求:
总时间限制: 1000ms
内存限制: 65536kB
描述:
求两个不超过200位的非负整数的积。
输入:
有两行,每行是一个不超过200位的非负整数,没有多余的前导0。
输出:
一行,即相乘后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。
样例输入:
12345678900 98765432100
样例输出:
1219326311126352690000
思路分析:
1 | 2 | 3 | |
x | 1 | 3 | |
3 | 6 | 9 | |
1 | 2 | 3 | 伸缩量 |
1 | 5 | 9 | 9 |
这个题目可以说是一个十分经典的题目了,基本的思路是用字符串来存储大整数,通过模仿竖式运算的方法计算出结果的每一位.
大整数乘法相较于大整数加法而言复杂的地方在于,它需要很多的中间大整数值进行相加,其中每一个都有若干个后置的‘0’. 那么,相乘和相加时的顺序就成为一个值得考虑的问题.
相乘时的顺序我们考虑,将第一个大整数与第二个大整数从左至右的每一位进行相乘,这样我们可以通过在循环中添加一行 ans.push_back('0'); 来模拟竖式运算中每一位相乘的结果向前的伸缩量.
每一位相乘后,我们得到的结果必然是倒序的.此时,不用急着转换回来,将倒序的中间值与ans进行计算,因为在大整数加法中,倒序更方便我们对齐.
最终代码:
#include<iostream>
#include<algorithm> //reverse 函数需要的头文件
using namespace std;
inline void PLUS(string& a,string& b){
reverse(a.begin(),a.end());
int s1=a.size(),s2=b.size();
int len=max(s1,s2);
/* compensate '0' to make the two sizes equal */
if(s1>s2) b.append(s1-s2,'0');
else a.append(s2-s1,'0');
int addition=0;
for(int i=0;i<len;i++){
int val=a[i]-'0'+b[i]-'0'+addition;
addition=val/10;
a[i]=(val%10)+'0';
}
if(addition) a.push_back(addition+'0');
reverse(a.begin(),a.end());// keep ans in the right direction
}
int main(){
string num1,num2,ans,tmp;
cin>>num1>>num2;
ans="0";
/* num2: from left to right */
for(auto i=num2.begin();i!=num2.end();i++){
ans.push_back('0');//伸缩量
int addition=0;//进位
int n2=(*i)-'0';
/* num1: from right to left */
for(auto j=num1.rbegin();j!=num1.rend();j++){
int n1=(*j)-'0';
int val=n1*n2+addition;
tmp.push_back((val%10)+'0');
addition=val/10;
}
if(addition) tmp.push_back(addition+'0');
/* tmp now is reversed while ans is always in the right direction */
PLUS(ans,tmp);
tmp.clear();
}
printf("%s\n",ans.c_str());
}