文章目录
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d6614f8229d7f0c7a72f33a23ba9ca16.png#pic_center)
一、高精度剖析与例题讲解
高精度问题是一类处理长度(位数)很长的正整数的运算问题(以下均讨论非负数)。在学习具体的问题之前,我们首先要学习超长整数是如何存储的。对于超长整数,用某种数据类型来存储其实是行不通的,我们会把它的每一位存到数组里。在存储时,数组的小下标存低位,大下标存高位。比如若把123456(当然它不是超长整数,我们只是举个例子)存到数组里,那么就是6 5 4 3 2 1。这样做是因为加减乘除可能涉及到进位,而在数组尾部进行数据的修改是比较容易的。注意:不要混淆位数和数值!比如说,若一个数的数值<=10,那么它的取值范围是0-10;若一个数的长度<=10,那么它的取值范围是0-9999999999。
高精度问题主要分为以下几类:
1.A+B(A,B位数很大,如1e6级别)
让我们先来回忆一下竖式加法的流程:
这里的ti(i = 0,1,2,3)表示进位,因此ti = 0或1。我们可以发现,Ci = (Ai + Bi + ti)%10。因此要实现超长整数相加,只需要把数组对应位置的数以及进位数加起来再模10,就可以得到新数字的每一位。 那么就让我们来看看代码如何实现吧!
#include <iostream>
#include<vector>
using namespace std;
//传引用,防止多开空间
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;
}
//如果到最后还有进位,就在C最后面补上一个1
if(t) C.push_back(1);
return C;
}
int main()
{
//用字符串的形式读数,可以拿到每一位
string a,b;
//定义大小可变化的数组
vector<int> A,B;
cin>>a>>b;
//由于读进来的形式是字符,因此为了拿到那一位,我们要减去偏移量,即字符0的ASCII码值。
//此外,我们要把数据倒着读进数组。
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--) printf("%d",C[i]);
return 0;
}
一定要好好看注释哦,作者想说的都在注释里啦!如果你感觉阅读本段代码有困难,不妨先看看这个——[
C++vector快速入门
2.A-B(A,B位数很大,如1e6级别)
数据的存储方式同上。那么相减的算法思想是怎样的呢?我们通过竖式计算图来观察一下:
我们可以发现,与加法不同的是减法需要借位。假设上一位借该位t(t=0或1),那么
>=0 不需要借位 那么直接减就可以 得到Ai - Bi - t | |
---|---|
Ai - Bi - t | |
<0 那么需要借位,也就是+10,得到Ai -Bi - t + 10 |
#include<iostream>
using namespace std;
#include<vector>
//判断是否有 A>=B
bool cmp(vector<int>&A,vector<int>&B)
{
if(A.size()!=B.size()) return A.size()>B.size();
for(int i = A.size()-1;i>=0;i--)
{
if(A[i]!=B[i]) return A[i]>B[i];
}
return true;
}
//C = A - B
//这里已经保证A>=B了
vector<int> sub(vector<int>&A,vector<int>&B)
{
vector<int> C;
//由于已经保证A>=B,所以A.size()>=