
第一章 基础算法(二)
高精度
高精度问题其实只有使用 C++ 编程语言的同学需要关注,使用 java 或 python 编程语言的同学不需要太多关注。因为 java 有大整数类,python 自带的数据范围默认就是无限大,而 C++ 没有相对应的处理大整数运算的数据结构。
高精度的考察主要分为四种: 高 精 度 { 加 法 A + B 减 法 A − B 乘 法 A × a 除 法 A ÷ a 高精度\begin{cases}加法 \quad A+B \\ 减法 \quad A-B \\ 乘法 \quad A \times a \\ 除法 \quad A \div a\end{cases} 高精度⎩⎪⎪⎪⎨⎪⎪⎪⎧加法A+B减法A−B乘法A×a除法A÷a,其中 A , B A,B A,B 的位数 ⩽ 1 0 6 \leqslant 10^6 ⩽106, a ⩽ 10000 a\leqslant 10000 a⩽10000。
两个大整数相乘/相除应用的场景不多,并且 A ÷ B A\div B A÷B 即两个大整数相除处理起来非常复杂,所以这里不作考虑。
如何存储大整数?
因为 C++ 中没有能够存储大整数的数据类型的,所以可以将大整数的每一位存在数组当中。
例如有一个大整数 A = 123456789 A=123456789 A=123456789,那么存储到数组当中时,会出现一个问题:**低位在前还是高位在前呢?**即假设有一个数组 s s s,则应该让 s [ 0 ] = 1 s[0]=1 s[0]=1 还是让 s [ 0 ] = 9 s[0]=9 s[0]=9?
应该是低位在前,即 s [ 0 ] = 9 , s [ 1 ] = 8 ⋯ s [ 8 ] = 1 s[0]=9,s[1]=8 \cdots s[8]=1 s[0]=9,s[1]=8⋯s[8]=1,这样存储会比较好。因为两个整数相加可能会存在进位,这样进位时会在高位的地方补上数字,而将高位存储到数组的末尾,可以更方便地新增数字。
即用 s [ 0 ] s[0] s[0] 存储整数的个位,用 s [ 1 ] s[1] s[1] 存储整数的十位,以此类推。
高精度加法
高精度加法是模拟人工加法的过程。
1 2 3 + 8 9 2 1 2 \begin{matrix} & 1 & 2 & 3 \\ + & & 8 & 9 \\ \hline & 2 & 1 & 2 \end{matrix} +12281392
所以对于两个大整数 A , B A,B A,B,加法运算就是模拟人工加法的过程,在从低位到高位相加时,考虑进位即可。
A 3 A 2 A 1 A 0 + B 2 B 1 B 0 C 3 C 2 C 1 C 0 \begin{matrix} & A_3 & A_2 & A_1 & A_0 \\ + & & B_2 & B_1 & B_0 \\ \hline & C_3 & C_2 & C_1 & C_0 \end{matrix} +A3C3A2B2C2A1B1C1A0B0C0
即 C 0 = ( A 0 + B 0 ) % 10 C_0=(A_0+B_0)\%10 C0=(A0+B0)%10;
若 A 0 + B 0 ⩾ 10 A_0+B_0\geqslant 10 A0+B0⩾10,则说明需要进位,故 C 1 = ( A 0 + B 0 ) / 10 + ( A 1 + B 1 ) % 10 C_1=(A_0+B_0)/10+(A_1+B_1)\%10 C1=(A0+B0)/10+(A1+B1)%10;
一般地,有 C i = ( A i − 1 + B i − 1 ) / 10 + ( A i + B i ) % 10 C_i=(A_{i-1}+B_{i-1})/10+(A_i+B_i)\%10 Ci=(Ai−1+Bi−1)/10+(Ai+Bi)%10;
如果 A i A_i Ai 或 B i B_i Bi 有其中一个不存在,则用 0 0 0 代替即可。
依次类推进行下去,就可以实现模拟人工加法。
AcWing 791. 高精度加法
给定两个正整数(不含前导 0 0 0),计算它们的和。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的和。
数据范围
1 ≤ 1≤ 1≤ 整数长度 ≤ 1 0 5 ≤10^5 ≤105
输入样例:
12
23
输出样例:
35
时/空限制: 1s / 64MB
来源: 模板题
算法标签:高精度
yxc’s Solution
- 在 C++ 编程语言中,可以使用
vector
来代替数组来存储大整数,因为vector
自带size
函数,可以表示数组的长度,就不需要开额外的变量,存储数组的长度这一信息了。
#include <iostream>
#include <vector>
using namespace std;
const int N = 1e6 + 10;
vector<int> add(vector<int> &A, vector<int> &B)
//这里使用引用&,是为了增加效率,如果不加引用,在调用函数时会将 A 和 B 都复制一遍,会增加耗时
{
vector<int> C;
int tmp = 0;
for (int i=0; i < A.size() || i < B.size(); i ++ )
{
if (i < A.size()) tmp += A[i];
if (i < B.size()) tmp += B[i];
C.push_back(tmp % 10);
tmp /= 10;
}
if (tmp) C.push_back(tmp);
return C;
}
int main()
{
string a, b;
vector<int> A, B;
cin >> a >> b; // a = "123456"
for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0'); // A = [6, 5, 4, 3, 2, 1]
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;
}
高精度减法
加减乘除的高精度运算中,大整数的存储方式都是一样的。这样更方便在需要多种运算的题目中统一变量的数据类型。
高精度减法也是模拟人工减法的过程。
1 2 3 − 8 9 3 4 \begin{matrix} & 1 & 2 & 3 \\ - & & 8 & 9 \\ \hline & & 3 & 4 \end{matrix} −1283394
对于两个大整数 A , B A,B A,B,其减法过程也是模拟人工减法的过程,从低位到高位进行相减和借位。
A 3 A 2 A 1 A 0 − B 2 B 1 B 0 C 3 C 2 C 1 C 0 \begin{matrix} \end{matrix}\begin{matrix} & A_3 & A_2 & A_1 & A_0 \\ - & & B_2 & B_1 & B_0 \\ \hline & C_3 & C_2 & C_1 & C_0 \end{matrix} −A3C3A2B2C2A1B1C1A0B0C0
即 C 0 = A 0 − B 0 C_0=A_0-B_0 C0=A0−B0;
若不够减(如 A i < B i A_i<B_i Ai<Bi)就需要借位,即 A i − B i { ⩾ 0 , A i − B i < 0 , A i − B i + 10 A_i-B_i\begin{cases} \geqslant 0 , & A_i-B_i \\ <0, & A_i-B_i+10\end{cases} Ai−Bi{ ⩾0,<0,Ai−BiAi−Bi+10,但若需要借位,则 A i + 1 A_{i+1} Ai+1 就会减去 1 1 1;
需要注意的是,高精度减法的模板是默认 A ⩾ B A\geqslant B A⩾B 的,这样可以避免运算结果是负数,如果 A < B A<B A<B,则将它们交换就可以使用高精度减法的模板了。
因为 A − B = − ( B − A ) A-B=-(B-A) A−B=−(B−A),故如果 A − B A-B A−