C++ / ACM 自学笔记 · v5.0

P2142 高精度减法

原题入口

对应章节:四、批量输入、大整数运算与提交检查 → (二) 大整数的加减乘除。

(一) 任务与输出目标

输出 A-B,结果可以为负。

(二) 建模与推导

先去掉多余前导零,再按长度与字典序比较绝对值。较大的绝对值减较小的,从个位开始减去借位;当前差为负时加 10,同时向下一位借 1。若 A<B,先输出负号,再计算 B-A。绝对值为 0 时不输出负号。

(三) 手算与过程

1000-1:个位借 1 得 9,借位穿过两个 0,结果为 999;1-1000 则为 -999。

按具体数据展开的处理与返回过程

(四) 带注释实现

完整源文件

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

string normalize(string s) {
    auto p = s.find_first_not_of('0');
    return p == string::npos ? "0" : s.substr(p); // 保留唯一的零表示。
}

void solve() {
    string a, b;
    cin >> a >> b;
    a = normalize(a);
    b = normalize(b);
    bool negative = a.size() < b.size() || (a.size() == b.size() && a < b);
    if (negative) {
        cout << '-';
        swap(a, b);
    } // 先确定符号,再做大数减小数。
    string result;
    int borrow = 0, j = b.size() - 1;
    for (int i = a.size() - 1; i >= 0; --i) {
        int value = a[i] - '0' - borrow - (j >= 0 ? b[j--] - '0' : 0);
        borrow = value < 0;
        if (borrow)
            value += 10;
        result.push_back('0' + value); // 借位在下一轮扣除。
    }
    while (result.size() > 1 && result.back() == '0')
        result.pop_back();
    reverse(result.begin(), result.end());
    cout << result << '\n';
}

signed main() {
    ios::sync_with_stdio(false); // 关闭同步,使用 cin 与 cout 完成输入输出。
    cin.tie(0), cout.tie(0);

    int T = 1; // 本题读入一组数据。
    // cin >> T; // 题目给出测试组数时开启,并在 solve 中处理一组。
    while (T--)
        solve();
}

(五) 复杂度

时间 \(O(n+m)\),空间 \(O(n+m)\)。

返回本章题解索引 · 返回全部题号索引

查阅笔记正文与全部题解 · Ctrl / ⌘ K