高精度运算里的最重要的思想就是将数值以字符串(string)的形式输出。然后利用容器(vector)进行逆序读入。再然后就是前一位的进位(加、乘)或借位(减除)根据所要进行的运算来运用不同的思想。
高精度的加法:
处理好前一位的进位
加法的习惯是从个位逐步向前运算,这就是为什么要逆序输入的原因。假设高精度的运算公式我们记为:A[i]+B[i]=C[i],进位设为t。那么C[i]该数位上的值为(A[i]+B[i]+t)%10。
题目:
给定两个正整数(不含前导 00),计算它们的和。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的和。
数据范围
1≤整数长度≤1000001≤整数长度≤100000
输入样例:
12
23
输出样例:
35
代码如下:
#include<iostream>
#include<vector>//使用vector容器前需包含此文件
using namespace std;
//vector(vector &v) ; //加上'&' 为引用数组v,则不需要再拷贝一份,提高效率
vector<int> add(vector<int> &A,vector<int> &B)
{
vector<int> C;
//进位标识符t
int t=0;
for(int i=0;i<B.size()||i<A.size();i++)
{
/*
两个if语句都是在判断A或B容器对应的数位上是否还有数据
如果没有则对应数位上是+0,即不加。
*/
if(i<A.size()) t+=A[i];
if(i<B.size()) t+=B[i];
//要的是t个位上的数
C.push_back(t%10);
//舍弃掉个位数,让t十位数上的值参与到下一位数的运算中
t/=10;
}
//如果t不等于零,则在最高位补1。对应数位相加(两位数的加法),进位是0或1;
if(t) C.push_back(1);
return C;
}
int main()
{
string a,b;
/*
vector<int> 把vector理解成一个数组,但与数组不同的是:
vector是动态储存,保存在堆中。
动态扩展是找到比原来更大的内存空间,将原数据拷贝到新空间,释放 原 空间
*/
vector<int> A,B;
cin >> a >> b;
/*
push_back()是将括号里的元素插入至尾部
A.push_back(a[i]-'0')//意味着将a[i]-'0'这个数插到A容器的最后面
但由于A容器中无元素,所以插到了第一位上
*/
//逆序读入,方便于运算
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');
vector<int> C=add(A,B);
//逆序输出
for(int i=C.size()-1;i>=0;i--) cout << C[i];
return 0;
}
----------------------------------------------------------------------------
高精度的减法:
处理好前一位的借位
假设对应的高精度的减法为:A[i]-B[i]=C[i]。那么C[i] 位数上对应的数值就为(A[i]-B[i]+t+10)%10。小细节:如果本位被借位了,t=-1,否则t=0。加10再mod10容纳了借位与不借位的两种情况。
题目:
给定两个正整数(不含前导 00),计算它们的差,计算结果可能为负数。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的差。
数据范围
1≤整数长度≤1051≤整数长度≤105
输入样例:
32
11
输出样例:
21
代码:
/*
C.back是C++标准库中的一个容器适配器,它基于底层容器实现了栈(stack)的功能。栈是一种遵循后进先出(LIFO)原则的数据结构,只允许在栈顶进行插入和删除操作。
C.back提供了以下几个主要的成员函数:
push:将元素压入栈顶。
pop:将栈顶元素弹出。
top:返回栈顶元素的引用,但不删除该元素。
empty:判断栈是否为空。
size:返回栈中元素的个数。
*/
#include<bits/stdc++.h>
#include<vector>
using namespace std;
/*
判断a与b的大小
*/
bool check(vector<int> &a,vector<int> &b)
{
//长度不相等,直接返回a.size()>b.size(),如果a.size()>b.size()则为真,否则为假
if(a.size()!=b.size()) return a.size()>b.size();
//长度不相等
for(int i=a.size();i>=0;i--)//从最高位开始判断
//如果最高位不相等
if(a[i]!=b[i])
//同上
return a[i]>b[i];
//两种情况都判断过还是没结果,说明a=b,直接返回真
return true;
}
//减,对应数位相减
vector<int> sub(vector<int> &a,vector<int> &b)
{
//经过check函数之后,a的大小一定大于b
vector<int> C;//定义容器C
int t=0;
for(int i=0;i<a.size();i++)
{
t+=a[i];
if(i<b.size()) t-=b[i];
//倘若相减为负数,那么需进行借位操作。为正也不影响
C.push_back((t+10)%10);
//重新对t赋值
if(t<0) t=-1;
else t=0;
}
//这一步是去前导0,如果用数组来做,那就是压缩数组C的体积
//注意即使全为0,那么就要保存最后一位
while(C.size()>1&&C.back()==0) C.pop_back();//去顶
return C;
}
int main()
{
string a,b;
cin >> a >> b;
vector<int> A,B,C;
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');
if(check(A,B))
{
C=sub(A,B);
for(int i=C.size()-1;i>=0;i--) cout << C[i];
return 0;
}
else
{
C=sub(B,A);
//如果A的长度小于B,提前输出一个符号
cout << "-";
for(int i=C.size()-1;i>=0;i--) cout << C[i];
return 0;
}
}
---------------------------------------------------------------------
高精度的乘法
这里的乘法与平日里所用的的不一致因为平日里的不好处理进位。
记录一下y总的思路:先计算出a的个位与小整数b的乘积记为t
则结果个上位的数值就为t % 10
对下一位的进位为t/10。
题目
给定两个非负整数(不含前导 00) A𝐴 和 B𝐵,请你计算 A×B𝐴×𝐵 的值。
输入格式
共两行,第一行包含整数 A𝐴,第二行包含整数 B𝐵。
输出格式
共一行,包含 A×B𝐴×𝐵 的值。
数据范围
1≤A的长度≤1000001≤𝐴的长度≤100000,
0≤B≤100000≤𝐵≤10000
输入样例:
2
3
输出样例:
6
代码:
#include<bits/stdc++.h>
#include<vector>
using namespace std;
/*
当该位的值 %10之后 ,所剩下的数就是该进制下的数。若想进位到前者
则需要/10。上一位的数放到下一位的时候权重就会少10。
'0'=48,'a'=97,'A'=65
*/
vector<int> mul(vector<int> a,int b)
{
vector<int> c;
int t=0;
//y总对算法思路的掌握当真是令我五体投地!!
/*这里||t的运用是我没能想到的,即是对最高位的
的进位。如果不加这一步,总会缺个最高位
*/
for(int i=0;i<a.size()||t;i++)
{
if(i<a.size()) t+=a[i]*b;
//每一位数的值。。如果最后数值已经乘完,只有进位时,按照此规律将其附在后面就行
c.push_back(t%10);
//进位
t/=10;
}
//去前导0(更简洁的做法是特判一下b是否为0)
while(c.size()>1&&c.back()==0) c.pop_back();
return c;
}
int main()
{
string a;
int b;
cin >> a >> b;
//倒序输入,方便运算
vector<int> c;
for(int i=a.size()-1;i>=0;i--) c.push_back(a[i]-'0');
vector<int> sum;
sum=mul(c,b);
//倒序输出
for(int i=sum.size()-1;i>=0;i--) cout << sum[i];
return 0;
}
----------------------------------------------------------------
高精度的除法:
也是对借位的处理。但是低位向高位借位时高位的权值会加10.
题目:
给定两个非负整数(不含前导 00) A,B𝐴,𝐵,请你计算 A/B𝐴/𝐵 的商和余数。
输入格式
共两行,第一行包含整数 A𝐴,第二行包含整数 B𝐵。
输出格式
共两行,第一行输出所求的商,第二行输出所求余数。
数据范围
1≤A的长度≤1000001≤𝐴的长度≤100000,
1≤B≤100001≤𝐵≤10000,
B𝐵 一定不为 00
输入样例:
7
2
输出样例:
3
1
代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> div(vector<int> &A,int &b,int &r)
{
vector<int> C;
/*
高精度的加、减、乘都是从原字符串的个位开始运算,而除法是从高位
向低位进行运算。为了保持四则输入输出的完整性,
在这里牺牲掉函数。
*/
//从最高位开始运算,而由于输入时是逆序输入,所以运算时从
//A容器的最后面开始运算,令i=A.size()-1
for(int i=A.size()-1;i>=0;i--)
{
/*余数r,该位的被除数等于这一位的数值+
上一位余数的十倍 (上一位是高位,降位权值扩大十倍)*/
r=r*10+A[i];
//结果的位数数值等于被除数/除数
C.push_back(r/b);
//取余
r=r%b;
}
//如上所述,为了保持输出(逆序)的一致性,在这里将正序的C再逆序一边。
reverse(C.begin(),C.end());//调用该函数需要包含#include<algorithm>头文件
//去前导0
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
int main()
{
string A;
int b;
cin >> A >>b;
vector<int> B,C;
//逆序输入
for(int i=A.size()-1;i>=0;i--) B.push_back(A[i]-'0');
int r=0;
C=div(B,b,r);
//逆序输出
for(int i=C.size()-1;i>=0;i--) cout << C[i];
cout << endl << r;
return 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];
C.push_back(t%10);
t/=10;
}
//特判最后一次运算是否需要进一
if(t) C.push_back(1);
return C;
}
int main()
{
string a,b;
cin >> a >> b;
vector<int> 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');
vector<int> C=add(A,B);
逆序输出
for(int i=C.size()-1;i>=0;i--) cout << C[i];
return 0;
}
高精度的减法 :
//一般为大数减小数。如果输入时为小数减大数,提前输出一个负号就可以了
bool check(vector<int> &a,vector<int> &b)
{
if(a.size()!=b.size()) return a.size()>b.size();
for(int i=a.size();i>=0;i--)
if(a[i]!=b[i])
return a[i]>b[i];
return true;
}
vector<int> sub(vector<int> &a,vector<int> &b)
{
vector<int> C;
int t=0;
for(int i=0;i<a.size();i++)
{
t+=a[i];
if(i<b.size()) t-=b[i];
C.push_back((t+10)%10);
if(t<0) t=-1;
else t=0;
}
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
高精度乘法:
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);
t/=10;
}
while(c.size()>1&&c.back()==0) c.pop_back();
return c;
}
高精度除法:
vector<int> div(vector<int> &A,int &b,int &r)
{
vector<int> C;
/*
高精度的加、减、乘都是从原字符串的个位开始运算,而除法是从高位
向低位进行运算。为了保持四则输入输出的完整性,
在这里牺牲掉函数。
*/
//从最高位开始运算,而由于输入时是逆序输入,所以运算时从
//A容器的最后面开始运算,令i=A.size()-1
for(int i=A.size()-1;i>=0;i--)
{
r=r*10+A[i];
C.push_back(r/b);
r=r%b;
}
//如上所述,为了保持输出(逆序)的一致性,在这里将正序的C再逆序一边。
reverse(C.begin(),C.end());
//去前导0
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
高精度 结束!!!