boolcmp(int A[], int B[]){ if (la != lb) return la > lb; for (int i = la - 1; ~i; i -- ) if (A[i] != B[i]) return A[i] > B[i]; returntrue; // 避免结果为 -0 }
2.2 vector
typedef vector<int> VI;
boolcmp(VI &A, VI &B){ if (A.size() != B.size()) return A.size() > B.size(); for (int i = A.size() - 1; ~i; i -- ) if (A[i] != B[i]) return A[i] > B[i]; returntrue; // 避免结果为 -0 }
3 高精度加法
时间复杂度: O(n) 算法步骤:
高精度数字利用字符串读入
把字符串翻转存入两个整型数组 A, B
从低位到高位, 累加, 进位, 存余 *
把数组 C 从高位到低位依次输出
3.1 数组
constint N = 1e5 + 10; int A[N], B[N], C[N]; // 表示三个大整数 int la, lb, lc; // 数组的实际大小/长度
voidadd(int A[], int B[], int C[]){ for (int i = 0; i < lc; i ++ ){ C[i] += A[i] + B[i]; // 累加 C[i + 1] += C[i] / 10; // 进位 C[i] %= 10; // 存余 } if (C[lc]) lc ++ ; // 处理最高位 }
intmain() { string a, b; cin >> a >> b; la = a.size(), lb = b.size(), lc = max(la, lb); for (int i = la - 1; ~i; i -- ) A[la - 1 - i] = a[i] - '0'; // 翻转存入数组 A for (int i = lb - 1; ~i; i -- ) B[lb - 1 - i] = b[i] - '0'; // 翻转存入数组 B add(A, B, C); for (int i = lc - 1; ~i; i -- ) printf("%d", C[i]); // 倒序输出数组 C return0; }
3.2 vector
typedef vector<int> VI; VI A, B, C; voidadd(VI &A, VI &B, VI &C);
intmain(void) { string a, b; cin >> a >> b; for (int i = a.size() - 1; ~i; i -- ) A.push_back(a[i] - '0'); // 翻转存入 A for (int i = b.size() - 1; ~i; i -- ) B.push_back(b[i] - '0'); // 翻转存入 B add(A, B, C); for (int i = C.size() - 1; ~i; i -- ) cout << C[i]; // 倒序输出 return0; }
voidadd(VI &A, VI &B, VI &C){ int t = 0; // 由 t 进行累加 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(t); // 处理最高位 }
4 高精度减法
时间复杂度: O(n) 算法步骤:
高精度数组利用字符串读入
把字符串翻转存入两个整型数组 A, B
若 A < B, 则交换 A, B, 输出负号 *
从低位到高位, 逐位求差, 借位, 存差 *
把数组 C 从高位到低位依次输出
4.1 数组
constint N = 1e5 + 10; int A[N], B[N], C[N]; int la, lb, lc; boolcmp(int A[], int B[]); voidsub(int A[], int B[], int C[]);
intmain(void) { string a, b; cin >> a >> b; la = a.size(), lb = b.size(), lc = max(la, lb); for (int i = la - 1; ~i; i -- ) A[la - 1 - i] = a[i] - '0'; // 翻转存入 A for (int i = lb - 1; ~i; i -- ) B[lb - 1 - i] = b[i] - '0'; // 翻转存入 B if (!cmp(A, B)) swap(A, B), cout << '-'; // 若 A < B, 则交换 A, B, 输出负号 sub(A, B, C); for (int i = lc; ~i; i -- ) cout << C[i]; return0; }
boolcmp(int A[], int B[]){ if (la != lb) return la > lb; for (int i = la - 1; ~i; i -- ) if (A[i] != B[i]) return A[i] > B[i]; returntrue; // 避免结果为 -0 }
voidsub(int A[], int B[], int C[]){ for (int i = 0; i < lc; i ++ ){ if (A[i] < B[i]) A[i + 1] --, A[i] += 10; // 借位 C[i] = A[i] - B[i]; // 存差 } while (lc && C[lc] == 0) lc--; // 处理前导0 }
4.2 vector
typedef vector<int> VI; VI A, B, C; boolcmp(VI &A, VI &B); voidsub(VI &A, VI &B, VI &C);
intmain(void) { string a, b; cin >> a >> b; for (int i = a.size() - 1; ~i; i -- ) A.push_back(a[i] - '0'); // 翻转存入 A for (int i = b.size() - 1; ~i; i -- ) B.push_back(b[i] - '0'); // 翻转存入 B if (!cmp(A, B)) swap(A, B), cout << "-"; // 若 A < B, 则交换 A, B, 输出负号 sub(A, B, C); for (int i = C.size() - 1; ~i; i -- ) cout << C[i]; return0; }
boolcmp(VI &A, VI &B){ if (A.size() != B.size()) return A.size() > B.size(); for (int i = A.size() - 1; ~i; i -- ) if (A[i] != B[i]) return A[i] > B[i]; returntrue; // 避免结果为 -0 }
voidsub(VI &A, VI &B, VI &C){ int t = 0; // t 存储借位 for (int i = 0; i < A.size(); i++){ t = A[i]; if (i < B.size()) t -= B[i]; if (t < 0) A[i + 1] --, t += 10; // 借位 C.push_back(t); // 存余 } while (C.size() > 1 && !C.back()) C.pop_back(); // 处理前导0 }
5 高精度乘法
时间复杂度 : O(n^2) 算法步骤:
高精度数组利用字符串读入
把字符串翻转存入两个整型数组 A, B
从低位到高位, 累加乘积, 进位, 存余 *
把数组 C 从高位到低位依次输出
5.1 数组
constint N = 1e5 + 10; int A[N], B[N], C[N]; int la, lb, lc; voidmul(int A[], int B[], int C[]);
intmain(void) { string a, b; cin >> a >> b; la = a.size(), lb = b.size(), lc = la + lb; for (int i = la - 1; ~i; i -- ) A[la - 1 - i] = a[i] - '0'; // 翻转存入 for (int i = lb - 1; ~i; i -- ) B[lb - 1 - i] = b[i] - '0'; // 翻转存入 mul(A, B, C); for (int i = lc; ~i; i -- ) cout << C[i]; // 逆序输出 return0; }
voidmul(int A[], int B[], int C[]){ for (int i = 0; i < la; i ++ ) for (int j = 0; j < lb; j ++ ){ C[i + j] += A[i] * B[j]; // 累加乘积 C[i + j + 1] += C[i + j] / 10; // 进位 C[i + j] %= 10; // 存余 } while (lc && C[lc] == 0) lc -- ; // 处理前导0(当有一个数为0时) }
5.2 vector
C 的初始化:
// 其一 VI A, B; intmain() { VI C(A.size() + B.size()); }
// 其二 VI A, B, C; intmain() { C.resize(A.size() + B.size()); }
typedef vector<int> VI; VI A, B, C; voidmul(VI &A, VI &B, VI &C);
intmain(void) { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); string a, b; cin >> a >> b; for (int i = a.size() - 1; ~i; i -- ) A.push_back(a[i] - '0'); for (int i = b.size() - 1; ~i; i -- ) B.push_back(b[i] - '0'); C.resize(A.size() + B.size()); mul(A, B, C); for (int i = C.size() - 1; ~i; i -- ) cout << C[i]; return0; }
voidmul(VI &A, VI &B, VI &C){ for (int i = 0; i < A.size(); i ++ ) for (int j = 0; j < B.size(); j ++ ){ C[i + j] += A[i] * B[j]; // 累加乘积 C[i + j + 1] += C[i + j] / 10; // 进位 C[i + j] %= 10; // 存余 } while (C.size() > 1 && !C.back()) C.pop_back(); // 处理前导0(当有一个数为0时) }
6 高精度除法
大整数 ÷ 小整数.
时间复杂度: O(n) 算法步骤:
高精度数组利用字符串读入
把字符串翻转存入两个整型数组 A, B
从高位到低位, 当前被除数, 存商, 求余数 *
把数组 C 从高位到低位依次输出
6.1 数组
typedeflonglong LL; LL r; // 计算当前被除数,或者说余数 constint N = 1e5 + 10; int A[N], b, C[N]; int la, lc; voiddiv(int A[], int b, int C[]);
intmain(void) { string a; cin >> a >> b; la = lc = a.size(); for (int i = la - 1; ~i; i -- ) A[la - 1 - i] = a[i] - '0'; // 翻转存入 div(A, b, C); for (int i = lc; ~i; i -- ) cout << C[i]; // 逆序输出 cout << endl << r << endl; return0; }
voiddiv(int A[], int b, int C[]){ r = 0; for (int i = la - 1; ~i; i -- ){ r = r * 10 + A[i]; // 被除数 C[la - 1 - i] = r / b; // 存商 r %= b; // 余数 } reverse(C, C + lc); while (lc && C[lc] == 0) lc -- ; // 处理多余0 }
6.3 vector
typedeflonglong LL; typedef vector<int> VI; LL r; // 计算当前被除数,或者说余数 VI A, C; int b; voiddiv(VI &A, int b, VI &C);
intmain(void) { string a; cin >> a >> b; for (int i = a.size() - 1; ~i; i -- ) A.push_back(a[i] - '0'); // 翻转存入 div(A, b, C); for (int i = C.size() - 1; ~i; i -- ) cout << C[i]; // 逆序输出 cout << endl << r << endl; return0; }
voiddiv(VI &A, int b, VI &C){ r = 0; for (int i = A.size() - 1; ~i; i -- ){ r = r * 10 + A[i]; // 被除数 C.push_back(r / b); // 存商 r %= b; // 余数 } reverse(C.begin(), C.end()); while (C.size() > 1 && !C.back()) C.pop_back(); // 处理多余0 }
// C = A + B, A >= 0, B >= 0 vector<int> add(vector<int> &A, vector<int> &B)// 默认 A > B { if (A.size() < B.size()) returnadd(B, A);
vector<int> C; int t = 0; // t 存储进位 for (int i = 0; i < A.size(); i ++ ){ // 以位数较大的 A 来遍历 t += A[i]; if (i < B.size()) t += B[i]; // 如果 B 还有剩余(A:1234,B:12) C.push_back(t % 10); // 把进位尾接到 C t /= 10; }
if (t) C.push_back(t); //如果循环后仍有进位,则将其作为最后一位添加到 C 中 return C; }
说明:
这里 t 存储进位 1
模板假设 A 和 B 都是非负大整数,即 A ≥ 0,B ≥ 0
假设大整数的位数 A ≥ B,不满足要交换参数次序
注意处理最高位进位(循环中,循环结束之后)
读取数组时反向 (n - 1 → 0) 遍历,运算时正向 (0 → n - 1) 遍历
高精度加法不会出现前导 0,而减法、乘法和除法会出现前导 0
7.2 高精度减法:
这里用大数减小数,若 A < B,则计算 -(B-A) 。因为 A 和 B 存在数组里,不能直接比大小,所以需要写一个 cmp() 函数进行比较,判断用谁减谁。
比如:1234 - 567 模拟一下:
// A >= B返回true,否则返回false boolcmp(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]; returntrue; }
// C = A - B, 满足 A >= B, A >= 0, B >= 0 vector<int> sub(vector<int> &A, vector<int> &B)// 默认 A >= B { vector<int> C; int t = 0; // t 存储借位 for (int i = 0; i < A.size(); i ++ ){ t = A[i] - t; if (i < B.size()) t -= B[i]; // 如果 B 还有剩余(A:1234,B:12) C.push_back((t + 10) % 10); // 涵盖 t 为正数负数两种情况 if (t < 0) t = 1; // 更新借位 else t = 0; }
乘法模板把对最高位的进位的处理翻到了 for 的循环条件中,这是与加法的主要区别。加法之所以能用一个 if 就能解决最高位的进位问题,是因为高精度加法最高位进位不会超过 10(实际上最多是 1),而高精度乘法的最高位进位可能超过 10,甚至更高,因此不能像加法那样处理
7.4 高精度除法:
// A / b = C ... r, A >= 0, b > 0 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]; C.push_back(r / b); r %= b; } reverse(C.begin(), C.end()); while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; }