1.1 高精度加法
给定两个正整数(不含前导 00),计算它们的和。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的和。
数据范围
1≤整数长度≤100000
输入样例:
12 23
输出样例:
35
- 思路:因为int最多只能2e9,longlong 最多只能9.2e18,对于题目要求的数字位数五万位是不行的,因此要把数据放入字符串自行模拟逢十进一。
- 开vector容器是因为系统中有自带的插入函数可以不用自己写循环来遍历
过程解析
for(int i=a.size()-1;i>=0;i--)
{
A.push_back(a[i]-'0');//加入a 中为1 2 3 A中为 3 2 1
}
for(int i=b.size()-1;i>=0;i--)
{
B.push_back(b[i]-'0');//倒序放入,进位的时候就是升序了
}
- 容器中的元素是逆序存放的,为了让进位的时候看起来更方便.假如说输入 123 456,存放在容器A,B分别就是321 654
- 这里的
a[i]-'0'
意思是把存入字符串的字符转化为数字
高精度函数加减模拟
vector<int> add(vector<int> &A,vector<int> &B)//值传递的话会更快,进函数不用拷贝
{
vector<int> C;
int t=0;//进位
for(int i=0;i<A.size()||i<B.size();i++)
{
if (i<A.size())t+=A[i];
if (i<B.size())t+=B[i];//t把A,B当前位数和进位相加
C.push_back(t%10);//如果t大于10 逢十进一 然后加入到容器C
t/=10;//加入说t=11,那么逢十进一
}
if(t)C.push_back(1);
- 函数t首先把A,B当前位的数字相加,如果相加大于10,那么就要进位1,t%10的意思是:如果在这位是9+9 那么当前位保留8,进1
- C容器存8,t=18,18/10=1,进位1保留到下一次相加.
- 假如输入样例是
985 ,34
,因为是逆序存放数组,次外层进入循环,由于最内层5+4<=0,因此t初始为0,8+3=11,当前位保留1,进1,此时数组中是91,然后最外层进入循环9+1=10
,10%10=0,因此 当前位插入0,10/10=1,t=1退出循环,此时数组中是910,最后if(t)C.push_back(1);
判断最高位的自增.再插入1,此时数组中是9101,遍历的时候逆序输出就是答案了.
源代码
#include<bits/stdc++.h>
using namespace std;
string a,b;
vector<int>A,B;
//写一个高精度加法,容器A加容器B
vector<int> add(vector<int> &A,vector<int> &B)//值传递的话会更快,进函数不用拷贝
{
vector<int> C;
int t=0;//进位
for(int i=0;i<A.size()||i<B.size();i++)
{
if (i<A.size())t+=A[i];
if (i<B.size())t+=B[i];//t把A,B当前位数和进位相加
C.push_back(t%10);//如果t大于10 逢十进一 然后加入到容器C
t/=10;//加入说t=11,那么逢十进一
}
if(t)C.push_back(1);//补充最高位的进位
//因为每次进位都是在循环立案增加的,因此最高位进位加不上
return C;//注意,C也要逆序输出,因为高位在后
}
int main()
{
cin>>a>>b;
for(int i=a.size()-1;i>=0;i--)
{
A.push_back(a[i]-'0');//加入a 中为1 2 3 A中为 3 2 1
}
for(int i=b.size()-1;i>=0;i--)
{
B.push_back(b[i]-'0');//倒序放入,进位的时候就是升序了
}
auto C=add(A,B);//此时的auto 就是vector <int> 类型
//遍历容器
for(int i=C.size()-1;i>=0;i--)
{
cout<<C[i];//容器除了这么遍历还可以用迭代器,写起来会麻烦一点
}
return 0;
}
1.2 高精度减法
给定两个正整数(不含前导 00),计算它们的差,计算结果可能为负数。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的差。
数据范围
1≤整数长度≤1051≤整数长度≤105
输入样例:
32 11
输出样例:
21
算法实现步骤
首先还是定义两个字符串然后把字符串里的数值转移到容器中
比较A数和B数的大小
一定是大数减去小数,这样能节省许多边界判断,因此定义了cmp函数
cmp函数
首先比较两个字符串的长度,如果长度相同就从高位往下比较位数哪个更大
if (a.size()!=b.size())return a.size()>b.size();//如果a长于b就返回1
其中我定义的cmp函数是这样的:
if (cmp(A,B))//A>B的时候是1
{
//A-B
}
else
{
//B-A
}
sub函数
定义的sub函数用于A-B,其中A>B
先定义一个容器C用于放答案,然后设定一个循环让每一位都相减
t=A[i]-t;
t是借位的意思
是每次进行运算之前都检查一下有没有借位,8-9时就需要借位,此时t=1,不需要的时候t=0
这行语句在赋值了A的那一位的同时处理了上一次运算的借位情况,因此接下来是t-=B[i];
模拟了A的某位-B的某位的情况,得到的值就是t
此时t有两种情况
- t>=0
- t<0
但是可以用(t+10)%10
归于一种情况
将t此时的值插入答案容器C中后,就需要判断这一轮需不需要借位了
if (t>=0)t=0;
else t=1;//往前面借一位
如果需要借位的话t=1不需要的话t=0
去除前导0
比如说123-34答案容器C中会得到980,那么这种情况需要去除后面多出来的0
可以巧妙的使用:while(C.size()>1&&VC.back()==0)C.pop_back();
来解决
意思是,当答案容器长度不小于1(即为0的情况),同时容器末尾为0时,去除0;
最后逆序输出答案就完事了
#include<bits/stdc++.h>
using namespace std;
string a,b;
vector<int>A,B;
bool cmp(vector<int>&A,vector<int>&B)//先比较位数,然后比较高位的大小
{
if (a.size()!=b.size())return a.size()>b.size();//如果a长于b就返回1
//如果a和b长度相同就逐个比较高位
for(int i=a.size()-1;i>=0;i--) //因为是反着存的,所以需要从后往前比较
{
if (A[i]!=B[i])return A[i]>B[i];
}
return true;//循环结束是两个数相同的情况 符合A>=B
}
//a-b运算
vector<int> sub(vector<int> &A,vector<int> &B)//此时,A>B,因为就算原先小于也调整过顺序了
{
int t=0;//t表示进位
vector<int> C;
for (int i=0;i<A.size();i++)//001 09 0 1 0
{
t=A[i]-t;
if(i<B.size())//如果B已经没有位数了例如123-34,b的位数有可能会被提前消耗完毕
{
t-=B[i];
}
//此时相当于A[i]-B[i],t可能大于0也可能小于0
C.push_back((t+10)%10);
if (t>=0)t=0;
else t=1;//往前面借一位
}
//去除前导0 比如说123-34会算出980,那么这种情况需要去除后面多出来的0
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
int main()
{
cin>>a>>b;
//两个字符串逆序放入容器
for (int i=a.size()-1;i>=0;i--)
{
A.push_back(a[i]-'0');
}
for(int i=b.size()-1;i>=0;i--)
{
B.push_back(b[i]-'0');
}
//如果A>B A-B
//A<B -(B-A)
if (cmp(A,B))//比较下来如果A>=B的话是1
{
auto C=sub(A,B);
//输出
for(int i=C.size()-1;i>=0;i--)cout<<C[i];
}
else
{
cout<<'-';
auto C=sub(B,A);
//输出
for(int i=C.size()-1;i>=0;i--)cout<<C[i];
}
return 0;
}
1.3 高精度乘法
1.3.1 高精度乘低精度
给定两个非负整数(不含前导 00) A和 B,请你计算 A×B 的值。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。
输出格式
共一行,包含 A×B 的值。
数据范围
1≤A的长度≤1000001
0≤B≤100000输入样例:
2 3
输出样例:
6
图例模拟:
#include <bits/stdc++.h>
using namespace std;
string a;
int b;
vector<int> A;
vector<int> mul(vector<int> &a,int b)
{
vector<int> C;
int t=0;
for (int i=0;i<A.size()||t;i++)
{
if (i<A.size())t+=A[i]*b;
C.push_back(t%10);//188 *81 648进64 712进71 152进15
//如果循环条件只有i<A.size()的话就已经结束了 ,接下来的部分是t还没有进完位数
//15进1,1进1,t=0结束
t/=10;//进位
}
//避免前导0 比如说12345 *0=00000
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
int main()
{
cin>>a>>b;
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
auto C=mul(A,b);
//输出
for(int i=C.size()-1;i>=0;i--)
{
cout<<C[i];
}
return 0;
}
1.3.2 高精度乘高精度
注解1:使用两层循环计算 A[i] 与 B[j] 的乘积,并将结果累加到 C[i+j]。为什么是C[i+j]?
这个乘法算法中,我们使用两层循环来遍历两个大数
A
和B
的每一位,并计算它们的乘积。考虑两个数字的乘法:
cssCopy code A = [a3, a2, a1, a0] B = [b2, b1, b0]
我们需要计算:
cssCopy code C = A * B
结果
C
的每一位都是由A
和B
中某两位的乘积决定的。例如:
C[0]
是由a0 * b0
决定的。C[1]
是由a1 * b0
和a0 * b1
的和决定的。C[2]
是由a2 * b0
、a1 * b1
和a0 * b2
的和决定的。C[3]
是由a3 * b0
、a2 * b1
、a1 * b2
和a0 * b3
的和决定的。在这里,
i+j
代表了A[i]
和B[j]
在结果C
中对应的位置。因此,我们累加每一位乘积到C[i+j]
。这种方式可以确保我们正确地计算出每一位的乘积,并将它们放置在正确的位置。
图例:
#include<bits/stdc++.h>
using namespace std;
string a,b;
vector<int>A,B;
//高精乘高精是运算和进位分开的,高精成低精是一边运算一边进位的
vector<int> mul(vector<int>&A,vector<int>&B)
{
//相乘的时候从低位开始乘
vector<int>C(A.size()+B.size());//开位数因为后面会有覆盖
for(int i=0;i<A.size();i++)
{
for(int j=0;j<B.size();j++)
{
C[i+j]+=A[i]*B[j];//见注解1
}
}
//有前导零的原因是因为初始化数组的时候vector<int>C(A.size()+B.size()),可能用不到那么多位数
//如果是12*12 C中是4 4 1 0
//如果是99*99 C中是81 162 81 0
//如果是12345*0 会是0 0 0 0 0
// for(int i=0;i<C.size();i++)printf("%d ",C[i]);
// cout<<endl;
//处理进位
int t=0;
for(int i=0;i<C.size()||t;i++)//判断条件是因为t在运算完之后会有几个还来不及进位。当 t 大于零时,我们继续进行处理,直到 t 为零为止。
{
if(i<C.size())t+=C[i];
//C.push_back(t%10);
C[i]=t%10;
t/=10;
}
//因为开的位数会多,所以要去除前导零
//去除前导零
while(C.size()>1&&C.back()==0)C.pop_back();
return C;
}
int main()
{
cin>>a>>b;
//逆序
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
for(int i=b.size()-1;i>=0;i--)B.push_back(b[i]-'0');
auto C=mul(A,B);
//输出
for(int i=C.size()-1;i>=0;i--)printf("%d",C[i]);
return 0;
}
1.4 高精度除法
给定两个非负整数(不含前导 00) A,B,请你计算 A/B的商和余数。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。
输出格式
共两行,第一行输出所求的商,第二行输出所求余数。
数据范围
1≤A的长度≤100000
1≤B≤10000
B一定不为 0输入样例:
7 2
输出样例:
3 1
图例:
一些提示:
代码中的r是通过改变地址而改变了其中的参数。s
#include<bits/stdc++.h>
using namespace std;
vector<int>A;
string a;
int b;
//除法运算
vector<int> div(vector<int> &A,int &b,int &r)
{
//除法是从高位开始除的
vector<int> C;
r=0;
for(int i=A.size()-1;i>=0;i--)
{
r=r*10+A[i];//r是被除数.r=1,12,13比如说123/11 第一步1/12=0 第二步12/11余1
C.push_back(r/b);
r%=b;
}
reverse(C.begin(),C.end());//和加减乘统一
//去除前导0 否则 运算10/9会输出 01 余1
while(C.size()>1&&C.back()==0)C.pop_back();
return C;
}
int main()
{
cin>>a>>b;
//逆序放入容器
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
//模拟除法运算(需要返回余数)
int r=0;
auto C=div(A,b,r);//r通过地址改变里面的值最后输出出来
//输出(正序)
for(int i=C.size()-1;i>=0;i--)
cout<<C[i];
cout<<endl<<r<<endl;
return 0;
}