1 条题解
-
0
自动搬运
来自洛谷,原作者为

MashPlant
**搬运于
2025-08-24 21:32:03,当前版本为作者最后更新于2018-03-27 22:27:49,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
更新一次~~
看到好多人卡到我前面去了,心情复杂,于是又写了一个更快一点的。现在16ms,还是第一。没有用vector,用起来的确有点麻烦。
除法的实现方法改了一下,改成每一个1e9之内二分答案,这样复杂度还是O(n^2),但是常数小了很多。
// luogu-judger-enable-o2 #include <cstring> #include <cstdio> #include <algorithm> #include <cassert> typedef int i32; typedef unsigned u32; typedef unsigned long long u64; struct BigInt { const static u32 exp = 9; const static u32 mod = 1000000000; static i32 abs_comp(const BigInt &lhs, const BigInt &rhs) { if (lhs.len != rhs.len) return lhs.len < rhs.len ? -1 : 1; for (u32 i = lhs.len - 1; ~i; --i) if (lhs.val[i] != rhs.val[i]) return lhs.val[i] < rhs.val[i] ? -1 : 1; return 0; } u32 *val, len, sgn; BigInt(u32 *val = nullptr, u32 len = 0, u32 sgn = 0) : val(val), len(len), sgn(sgn) {} // copy_to cannot guarantee val[x] == 0 for x >= len // other function should set (the position they assume to be zero) as zero void copy_to(BigInt &dst) const { dst.len = len, dst.sgn = sgn; memcpy(dst.val, val, sizeof(u32) * len); } void trim() { while (len && !val[len - 1]) --len; if (len == 0) sgn = 0; } void add(BigInt &x) { if (sgn ^ x.sgn) return x.sgn ^= 1, sub(x); val[len = std::max(len, x.len)] = 0; for (u32 i = 0; i < x.len; ++i) if ((val[i] += x.val[i]) >= mod) val[i] -= mod, ++val[i + 1]; for (u32 i = x.len; i < len && val[i] >= mod; ++i) val[i] -= mod, ++val[i + 1]; if (val[len]) ++len; } void sub(BigInt &x) { if (sgn ^ x.sgn) return x.sgn ^= 1, add(x); if (abs_comp(*this, x) < 0) std::swap(*this, x), sgn ^= 1; val[len] = 0; for (u32 i = 0; i < x.len; ++i) if ((val[i] -= x.val[i]) & 0x80000000) val[i] += mod, --val[i + 1]; for (u32 i = x.len; i < len && val[i] & 0x80000000; ++i) val[i] += mod, --val[i + 1]; trim(); } void mul(BigInt &x, u32 *ext_mem) { assert(this != &x); memcpy(ext_mem, val, sizeof(u32) * len); memset(val, 0, sizeof(u32) * (len + x.len)); for (u32 i = 0; i < len; ++i) for (u32 j = 0; j < x.len; ++j) { u64 tmp = (u64)ext_mem[i] * x.val[j] + val[i + j]; val[i + j] = tmp % mod; val[i + j + 1] += tmp / mod; } len += x.len, sgn ^= x.sgn; trim(); } void mul(u32 x) { if (x & 0x80000000) x = -x, sgn ^= 1; u64 carry = 0; for (u32 i = 0; i < len; ++i) { carry += (u64)val[i] * x; val[i] = carry % mod; carry /= mod; } if (carry) val[len++] = carry; trim(); } void div(BigInt &x, BigInt &remainder, u32 *ext_mem) { assert(this != &x && this != &remainder); copy_to(remainder), memset(val, 0, sizeof(u32) * len); u32 shift = len - x.len; if (shift & 0x80000000) return void(len = sgn = 0); while (~shift) { u32 l = 0, r = mod; BigInt mul_test{ext_mem}, remainder_high{remainder.val + shift, remainder.len - shift}; while (l <= r) { u32 mid = (l + r) / 2; x.copy_to(mul_test), mul_test.mul(mid); abs_comp(mul_test, remainder_high) < 0 ? l = mid + 1 : r = mid - 1; } val[shift] = r; x.copy_to(mul_test), mul_test.mul(r); remainder_high.sub(mul_test), remainder.trim(); --shift; } sgn ^= x.sgn; trim(); } void div(u32 x) { if (x & 0x80000000) x = -x, sgn ^= 1; u64 carry = 0; for (u32 i = len - 1; ~i; --i) { carry = carry * mod + val[i]; val[i] = carry / x; carry %= x; } trim(); } void read(const char *s) { sgn = len = 0; i32 bound = 0, pos; if (s[0] == '-') sgn = bound = 1; u64 cur = 0, pow = 1; for (pos = strlen(s) - 1; pos + 1 >= exp + bound; pos -= exp, val[len++] = cur, cur = 0, pow = 1) for (i32 i = pos; i + exp > pos; --i) cur += (s[i] - '0') * pow, pow *= 10; for (cur = 0, pow = 1; pos >= bound; --pos) cur += (s[pos] - '0') * pow, pow *= 10; if (cur) val[len++] = cur; } void print() { if (len) { if (sgn) putchar('-'); printf("%u", val[len - 1]); for (u32 i = len - 2; ~i; --i) printf("%0*u", exp, val[i]); } else putchar('0'); puts(""); } }; const int N = 1e4 + 20; u32 a_[N], b_[N], r_[N], tmp[N * 2]; char sa[N], sb[N]; int main() { scanf("%s%s", sa, sb); { BigInt a{a_}, b{b_}; a.read(sa), b.read(sb), a.add(b), a.print(); } { BigInt a{a_}, b{b_}; a.read(sa), b.read(sb), a.sub(b), a.print(); } { BigInt a{a_}, b{b_}; a.read(sa), b.read(sb), a.mul(b, tmp), a.print(); } { BigInt a{a_}, b{b_}, r{r_}; a.read(sa), b.read(sb), a.div(b, r, tmp), a.print(); r.print(); } }
各位C++大佬,速度比不过python你们的心不会痛吗?
76ms,目前第一,干掉python,算是维护一下C++的尊严吧。
除法的思路是倍增,记n为输入串的长度(而非输入串代表的数值大小),则倍增的判断次数是O(n),每次判断只涉及到加法,复杂度也是O(n),总体O(n^2)。二分查找的话,每次判断都是乘法,总体复杂度O(n^3)。
// luogu-judger-enable-o2 #include <bits/stdc++.h> class BigInt { #define Value(x, nega) ((nega) ? -(x) : (x)) #define At(vec, index) ((index) < vec.size() ? vec[(index)] : 0) //C风格的比较函数,其正负等于abs(lhs)-abs(rhs)的正负 static int absComp(const BigInt &lhs, const BigInt &rhs) { if (lhs.size() != rhs.size()) return lhs.size() < rhs.size() ? -1 : 1; for (int i = lhs.size() - 1; i >= 0; --i) if (lhs[i] != rhs[i]) return lhs[i] < rhs[i] ? -1 : 1; return 0; } using Long = long long; const static int Exp = 9; const static Long Mod = 1000000000; mutable std::vector<Long> val; mutable bool nega = false; //规定:0的nega必须是false,0的size必须是0 void trim() const { while (val.size() && val.back() == 0) val.pop_back(); if (val.empty()) nega = false; } int size() const { return val.size(); } Long &operator[](int index) const { return val[index]; } Long &back() const { return val.back(); } BigInt(int size, bool nega) : val(size), nega(nega) {} BigInt(const std::vector<Long> &val, bool nega) : val(val), nega(nega) {} public: friend std::ostream &operator<<(std::ostream &os, const BigInt &n) { if (n.size()) { if (n.nega) putchar('-'); for (int i = n.size() - 1; i >= 0; --i) { if (i == n.size() - 1) printf("%lld", n[i]); else printf("%0*lld", n.Exp, n[i]); } } else putchar('0'); return os; } friend BigInt operator+(const BigInt &lhs, const BigInt &rhs) { BigInt ret(lhs); return ret += rhs; } friend BigInt operator-(const BigInt &lhs, const BigInt &rhs) { BigInt ret(lhs); return ret -= rhs; } BigInt(Long x = 0) { if (x < 0) x = -x, nega = true; while (x >= Mod) val.push_back(x % Mod), x /= Mod; if (x) val.push_back(x); } BigInt(const char *s) { int bound = 0, pos; if (s[0] == '-') nega = true, bound = 1; Long cur = 0, pow = 1; for (pos = strlen(s) - 1; pos >= Exp + bound - 1; pos -= Exp, val.push_back(cur), cur = 0, pow = 1) for (int i = pos; i > pos - Exp; --i) cur += (s[i] - '0') * pow, pow *= 10; for (cur = 0, pow = 1; pos >= bound; --pos) cur += (s[pos] - '0') * pow, pow *= 10; if (cur) val.push_back(cur); } BigInt &operator+=(const BigInt &rhs) { const int cap = std::max(size(), rhs.size()) + 1; val.resize(cap); int carry = 0; for (int i = 0; i < cap - 1; ++i) { val[i] = Value(val[i], nega) + Value(At(rhs, i), rhs.nega) + carry, carry = 0; if (val[i] >= Mod) val[i] -= Mod, carry = 1; //至多只需要减一次,不需要取模 else if (val[i] < 0) val[i] += Mod, carry = -1; //同理 } if ((val.back() = carry) == -1) //assert(val.back() == 1 or 0 or -1) { nega = true, val.pop_back(); bool tailZero = true; for (int i = 0; i < cap - 1; ++i) { if (tailZero && val[i]) val[i] = Mod - val[i], tailZero = false; else val[i] = Mod - 1 - val[i]; } } trim(); return *this; } friend BigInt operator-(const BigInt &rhs) { BigInt ret(rhs); ret.nega ^= 1; return ret; } BigInt &operator-=(const BigInt &rhs) { rhs.nega ^= 1; *this += rhs; rhs.nega ^= 1; return *this; } //高精*高精没办法原地操作,所以实现operator* //高精*低精可以原地操作,所以operator*= friend BigInt operator*(const BigInt &lhs, const BigInt &rhs) { const int cap = lhs.size() + rhs.size() + 1; BigInt ret(cap, lhs.nega ^ rhs.nega); //j < l.size(),i - j < rhs.size() => i - rhs.size() + 1 <= j for (int i = 0; i < cap - 1; ++i) // assert(0 <= ret[cap-1] < Mod) for (int j = std::max(i - rhs.size() + 1, 0), up = std::min(i + 1, lhs.size()); j < up; ++j) { ret[i] += lhs[j] * rhs[i - j]; ret[i + 1] += ret[i] / Mod, ret[i] %= Mod; } ret.trim(); return ret; } BigInt &operator*=(const BigInt &rhs) { return *this = *this * rhs; } friend BigInt operator/(const BigInt &lhs, const BigInt &rhs) { static std::vector<BigInt> powTwo{BigInt(1)}; static std::vector<BigInt> estimate; estimate.clear(); if (absComp(lhs, rhs) < 0) return BigInt(); BigInt cur = rhs; int cmp; while ((cmp = absComp(cur, lhs)) <= 0) { estimate.push_back(cur), cur += cur; if (estimate.size() >= powTwo.size()) powTwo.push_back(powTwo.back() + powTwo.back()); } if (cmp == 0) return BigInt(powTwo.back().val, lhs.nega ^ rhs.nega); BigInt ret = powTwo[estimate.size() - 1]; cur = estimate[estimate.size() - 1]; for (int i = estimate.size() - 1; i >= 0 && cmp != 0; --i) if ((cmp = absComp(cur + estimate[i], lhs)) <= 0) cur += estimate[i], ret += powTwo[i]; ret.nega = lhs.nega ^ rhs.nega; return ret; } bool operator==(const BigInt &rhs) const { return nega == rhs.nega && val == rhs.val; } bool operator!=(const BigInt &rhs) const { return nega != rhs.nega || val != rhs.val; } bool operator>=(const BigInt &rhs) const { return !(*this < rhs); } bool operator>(const BigInt &rhs) const { return !(*this <= rhs); } bool operator<=(const BigInt &rhs) const { if (nega && !rhs.nega) return true; if (!nega && rhs.nega) return false; int cmp = absComp(*this, rhs); return nega ? cmp >= 0 : cmp <= 0; } bool operator<(const BigInt &rhs) const { if (nega && !rhs.nega) return true; if (!nega && rhs.nega) return false; return (absComp(*this, rhs) < 0) ^ nega; } void swap(const BigInt &rhs) const { std::swap(val, rhs.val); std::swap(nega, rhs.nega); } }; const int N = 1e4 + 10; char a[N], b[N]; int main() { scanf("%s%s", a, b); BigInt ba(a), bb(b); std::cout << ba + bb << '\n'; std::cout << ba - bb << '\n'; std::cout << ba * bb << '\n'; BigInt d; std::cout << (d = ba / bb) << '\n'; std::cout << ba - d * bb << '\n'; return 0; }
- 1
信息
- ID
- 899
- 时间
- 3000ms
- 内存
- 125MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者