cp-library-cpp

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub suisen-cp/cp-library-cpp

:heavy_check_mark: test/src/math/bigint/NTL_2_A.test.cpp

Depends on

Code

#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/6/NTL/all/NTL_2_A"

#include <iostream>

#include "library/math/bigint.hpp"
using suisen::bigint;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    bigint a, b;
    std::cin >> a >> b;
    std::cout << a + b << std::endl;
    return 0;
}
#line 1 "test/src/math/bigint/NTL_2_A.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/6/NTL/all/NTL_2_A"

#include <iostream>

#line 1 "library/math/bigint.hpp"



#line 1 "library/math/unsigned_bigint.hpp"



#include <iomanip>
#line 6 "library/math/unsigned_bigint.hpp"
#include <sstream>
#include <vector>

#line 1 "library/convolution/arbitrary_mod_convolution.hpp"



#include <atcoder/convolution>
#line 6 "library/convolution/arbitrary_mod_convolution.hpp"

#line 1 "library/convolution/convolution_naive.hpp"



#line 5 "library/convolution/convolution_naive.hpp"

namespace suisen::internal {
    template <typename T, typename R = T>
    std::vector<R> convolution_naive(const std::vector<T>& a, const std::vector<T>& b) {
        const int n = a.size(), m = b.size();
        std::vector<R> c(n + m - 1);
        if (n < m) {
            for (int j = 0; j < m; j++) for (int i = 0; i < n; i++) c[i + j] += R(a[i]) * b[j];
        } else {
            for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) c[i + j] += R(a[i]) * b[j];
        }
        return c;
    }
} // namespace suisen



#line 8 "library/convolution/arbitrary_mod_convolution.hpp"

namespace suisen {
    template <typename mint, atcoder::internal::is_modint_t<mint>* = nullptr>
    std::vector<mint> arbitrary_mod_convolution(const std::vector<mint>& a, const std::vector<mint>& b) {
        int n = int(a.size()), m = int(b.size());

        if constexpr (atcoder::internal::is_static_modint<mint>::value) {
            if constexpr (not (mint::mod() & 63)) {
                int maxz = 1;
                while (not ((mint::mod() - 1) & maxz)) maxz <<= 1;
                int z = 1;
                while (z < n + m - 1) z <<= 1;
                if (z <= maxz) return atcoder::convolution<mint>(a, b);
            }
        }

        if (n == 0 or m == 0) return {};
        if (std::min(n, m) <= 120) return internal::convolution_naive(a, b);

        static constexpr long long MOD1 = 754974721;  // 2^24
        static constexpr long long MOD2 = 167772161;  // 2^25
        static constexpr long long MOD3 = 469762049;  // 2^26
        static constexpr long long M1M2 = MOD1 * MOD2;
        static constexpr long long INV_M1_MOD2 = atcoder::internal::inv_gcd(MOD1, MOD2).second;
        static constexpr long long INV_M1M2_MOD3 = atcoder::internal::inv_gcd(M1M2, MOD3).second;

        std::vector<int> a2(n), b2(m);
        for (int i = 0; i < n; ++i) a2[i] = a[i].val();
        for (int i = 0; i < m; ++i) b2[i] = b[i].val();

        auto c1 = atcoder::convolution<MOD1>(a2, b2);
        auto c2 = atcoder::convolution<MOD2>(a2, b2);
        auto c3 = atcoder::convolution<MOD3>(a2, b2);

        const long long m1m2 = mint(M1M2).val();
        std::vector<mint> c(n + m - 1);
        for (int i = 0; i < n + m - 1; ++i) {
            // Garner's Algorithm
            // X = x1 + x2 * m1 + x3 * m1 * m2
            // x1 = c1[i], x2 = (c2[i] - x1) / m1 (mod m2), x3 = (c3[i] - x1 - x2 * m1) / m2 (mod m3)
            long long x1 = c1[i];
            long long x2 = (atcoder::static_modint<MOD2>(c2[i] - x1) * INV_M1_MOD2).val();
            long long x3 = (atcoder::static_modint<MOD3>(c3[i] - x1 - x2 * MOD1) * INV_M1M2_MOD3).val();
            c[i] = x1 + x2 * MOD1 + x3 * m1m2;
        }
        return c;
    }

    std::vector<__uint128_t> convolution_int(const std::vector<int> &a, const std::vector<int> &b) {
        int n = int(a.size()), m = int(b.size());

        auto check_nonnegative = [](int e) { return e >= 0; };
        assert(std::all_of(a.begin(), a.end(), check_nonnegative));
        assert(std::all_of(b.begin(), b.end(), check_nonnegative));

        if (n == 0 or m == 0) return {};
        if (std::min(n, m) <= 120) return internal::convolution_naive<int, __uint128_t>(a, b);

        static constexpr long long MOD1 = 754974721;  // 2^24
        static constexpr long long MOD2 = 167772161;  // 2^25
        static constexpr long long MOD3 = 469762049;  // 2^26
        static constexpr long long M1M2 = MOD1 * MOD2;
        static constexpr long long INV_M1_MOD2 = atcoder::internal::inv_gcd(MOD1, MOD2).second;
        static constexpr long long INV_M1M2_MOD3 = atcoder::internal::inv_gcd(M1M2, MOD3).second;

        auto c1 = atcoder::convolution<MOD1>(a, b);
        auto c2 = atcoder::convolution<MOD2>(a, b);
        auto c3 = atcoder::convolution<MOD3>(a, b);
        std::vector<__uint128_t> c(n + m - 1);
        for (int i = 0; i < n + m - 1; ++i) {
            // Garner's Algorithm
            // X = x1 + x2 * m1 + x3 * m1 * m2
            // x1 = c1[i], x2 = (c2[i] - x1) / m1 (mod m2), x3 = (c3[i] - x1 - x2 * m1) / m2 (mod m3)
            int x1 = c1[i];
            int x2 = (atcoder::static_modint<MOD2>(c2[i] - x1) * INV_M1_MOD2).val();
            int x3 = (atcoder::static_modint<MOD3>(c3[i] - x1 - x2 * MOD1) * INV_M1M2_MOD3).val();
            c[i] = x1 + x2 * MOD1 + __uint128_t(x3) * M1M2;
        }
        return c;
    }
} // namespace suisen



#line 10 "library/math/unsigned_bigint.hpp"

namespace suisen {
    struct unsigned_bigint : private std::vector<int> {
        static constexpr int D = 1000000000;
        static constexpr int LogD = 9;

        static inline struct { operator unsigned_bigint() const { return unsigned_bigint{}; }; } const ZERO{};
        static inline struct { operator unsigned_bigint() const { return unsigned_bigint{ 1 }; }; } const ONE{};

        unsigned_bigint() : vector() {}

        template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
        unsigned_bigint(T v) {
            if constexpr (std::is_signed_v<T>) {
                assert(v >= 0);
            }
            for (; v; v /= D) {
                this->push_back(v % D);
            }
        }
        unsigned_bigint(const std::string& s) : vector() {
            int siz = s.size();
            for (int i = siz; i > 0; i -= LogD) {
                int l = std::max(0, i - LogD);
                int r = i;
                int& v = this->emplace_back();
                for (int j = l; j < r; ++j) {
                    int d = s[j] - '0';
                    assert(0 <= d and d <= 9);
                    v = v * 10 + d;
                }
            }
        }
        unsigned_bigint(const char* s) : unsigned_bigint(std::string(s)) {}

        operator bool() const {
            return not this->empty();
        }

        friend bool operator==(const unsigned_bigint& a, const unsigned_bigint& b) {
            if (a.size() != b.size()) {
                return false;
            }
            for (size_t i = 0; i < a.size(); ++i) {
                if (a[i] != b[i]) return false;
            }
            return true;
        }
        friend bool operator!=(const unsigned_bigint& a, const unsigned_bigint& b) {
            return not (a == b);
        }
        friend bool operator<(const unsigned_bigint& a, const unsigned_bigint& b) {
            if (a.size() != b.size()) {
                return a.size() < b.size();
            }
            for (size_t i = a.size(); i-- > 0;) {
                if (a[i] != b[i]) return a[i] < b[i];
            }
            return false;
        }
        friend bool operator<=(const unsigned_bigint& a, const unsigned_bigint& b) {
            return not (b < a);
        }
        friend bool operator>(const unsigned_bigint& a, const unsigned_bigint& b) {
            return b < a;
        }
        friend bool operator>=(const unsigned_bigint& a, const unsigned_bigint& b) {
            return not (a < b);
        }

        friend unsigned_bigint& operator<<=(unsigned_bigint& a, int shamt) {
            if (a) a.insert(a.begin(), shamt, 0);
            return a;
        }
        friend unsigned_bigint operator<<(unsigned_bigint a, int shamt) {
            a <<= shamt;
            return a;
        }
        friend unsigned_bigint& operator>>=(unsigned_bigint& a, int shamt) {
            a.erase(a.begin(), a.begin() + std::min<int>(shamt, a.size()));
            return a;
        }
        friend unsigned_bigint operator>>(unsigned_bigint a, int shamt) {
            a >>= shamt;
            return a;
        }

        unsigned_bigint& operator++() {
            return _incr_assign(*this);
        }
        unsigned_bigint operator++(int) {
            unsigned_bigint res = *this;
            _incr_assign(*this);
            return res;
        }
        unsigned_bigint& operator--() {
            return _decr_assign(*this);
        }
        unsigned_bigint operator--(int) {
            unsigned_bigint res = *this;
            _decr_assign(*this);
            return res;
        }
        friend unsigned_bigint& operator+=(unsigned_bigint& a, const unsigned_bigint& b) {
            return _add_assign(a, b);
        }
        friend unsigned_bigint operator+(const unsigned_bigint& a, const unsigned_bigint& b) {
            unsigned_bigint c = a;
            c += b;
            return c;
        }
        friend unsigned_bigint& operator-=(unsigned_bigint& a, const unsigned_bigint& b) {
            return _sub_assign(a, b);
        }
        friend unsigned_bigint operator-(const unsigned_bigint& a, const unsigned_bigint& b) {
            unsigned_bigint c = a;
            c -= b;
            return c;
        }
        friend unsigned_bigint& operator*=(unsigned_bigint& a, const unsigned_bigint& b) {
            return a = a * b;
        }
        friend unsigned_bigint operator*(const unsigned_bigint& a, const unsigned_bigint& b) {
            return _mul_fft(a, b);
        }

        static std::pair<unsigned_bigint, unsigned_bigint> divmod(unsigned_bigint a, unsigned_bigint b) {
            return _divmod(a, b);
        }
        friend unsigned_bigint& operator/=(unsigned_bigint& a, const unsigned_bigint& b) {
            return a = a / b;
        }
        friend unsigned_bigint operator/(const unsigned_bigint& a, const unsigned_bigint& b) {
            return divmod(a, b).first;
        }
        friend unsigned_bigint& operator%=(unsigned_bigint& a, const unsigned_bigint& b) {
            return a = a % b;
        }
        friend unsigned_bigint operator%(const unsigned_bigint& a, const unsigned_bigint& b) {
            return divmod(a, b).second;
        }

#define CAST_PRIMITIVE(type)                                        \
    operator type() const {                                         \
        type res = 0;                                               \
        for (auto it = this->rbegin(); it != this->rend(); ++it) {  \
            res = res * D + *it;                                    \
        }                                                           \
        return res;                                                 \
    }                                                               \

        CAST_PRIMITIVE(unsigned int)
            CAST_PRIMITIVE(unsigned long)
            CAST_PRIMITIVE(unsigned long long)
            CAST_PRIMITIVE(__uint128_t)
            CAST_PRIMITIVE(float)
            CAST_PRIMITIVE(double)
            CAST_PRIMITIVE(long double)
#undef CAST_PRIMITIVE

#define CAST_SIGNED_INT(type)                                   \
    operator type() const {                                     \
        return static_cast<std::make_unsigned_t<type>>(*this);  \
    }                                                           \

            CAST_SIGNED_INT(int)
            CAST_SIGNED_INT(long)
            CAST_SIGNED_INT(long long)
#undef CAST_SIGNED_INT

            operator __int128_t() const {
            return static_cast<__uint128_t>(*this);
        }

        operator std::string() const {
            return _to_string();
        }

        friend std::istream& operator>>(std::istream& in, unsigned_bigint& v) {
            std::string s;
            in >> s, v = s;
            return in;
        }
        friend std::ostream& operator<<(std::ostream& out, const unsigned_bigint& v) {
            return out << v._to_string();
        }
    private:
        using std::vector<int>::vector;

        void _check_leading_zeros() const {
            assert(this->empty() or this->back());
        }

        void _cut_leading_zeros() {
            while (this->size() and this->back() == 0) this->pop_back();
        }

        static unsigned_bigint& _incr_assign(unsigned_bigint& a) {
            for (int& e : a) {
                if (++e != D) return a;
                e -= D;
            }
            a.push_back(1);
            return a;
        }
        static unsigned_bigint& _decr_assign(unsigned_bigint& a) {
            assert(a.size());
            for (int& e : a) {
                if (--e >= 0) break;
                e += D;
            }
            a._cut_leading_zeros();
            return a;
        }

        static unsigned_bigint& _add_assign(unsigned_bigint& a, const unsigned_bigint& b) {
            if (a.size() < b.size()) a.resize(b.size());
            int carry = 0;
            for (size_t i = 0; i < a.size(); ++i) {
                if (i >= b.size()) {
                    if (carry) {
                        ++a[i];
                    } else break;
                } else {
                    a[i] += b[i] + carry;
                }
                if (a[i] >= D) {
                    a[i] -= D;
                    carry = 1;
                } else {
                    carry = 0;
                }
            }
            if (carry) a.push_back(1);
            return a;
        }

        static unsigned_bigint& _sub_assign(unsigned_bigint& a, const unsigned_bigint& b) {
            assert(a.size() >= b.size());
            int borrow = 0;
            for (size_t i = 0; i < a.size(); ++i) {
                if (i >= b.size()) {
                    if (borrow) {
                        --a[i];
                    } else break;
                } else {
                    a[i] -= b[i] + borrow;
                }
                if (a[i] < 0) {
                    a[i] += D;
                    borrow = 1;
                } else {
                    borrow = 0;
                }
            }
            assert(not borrow);
            a._cut_leading_zeros();
            return a;
        }

        unsigned_bigint _cut(int l, int r) const {
            r = std::min(r, static_cast<int>(this->size()));
            unsigned_bigint v = l < r ? unsigned_bigint(this->begin() + l, this->begin() + r) : ZERO;
            v._cut_leading_zeros();
            return v;
        }

        template <typename T>
        static unsigned_bigint _build(const std::vector<T>& dat) {
            unsigned_bigint res;
            T carry = 0;
            for (auto v : dat) {
                carry += v;
                res.push_back(carry % D);
                carry /= D;
            }
            while (carry) {
                res.push_back(carry % D);
                carry /= D;
            }
            res._cut_leading_zeros();
            return res;
        }

        static unsigned_bigint _mul_naive(const unsigned_bigint& a, const unsigned_bigint& b) {
            return _build(suisen::internal::convolution_naive<int, __int128_t>(a, b));
        }

        static unsigned_bigint _mul_karatsuba(const unsigned_bigint& a, const unsigned_bigint& b) {
            if (std::min(a.size(), b.size()) <= 64) {
                return _mul_naive(a, b);
            }
            const int m = std::max(a.size(), b.size()) / 2;

            unsigned_bigint lo_a = a._cut(0, m), hi_a = a._cut(m, a.size());
            unsigned_bigint lo_b = b._cut(0, m), hi_b = b._cut(m, b.size());

            unsigned_bigint lo_c = lo_a * lo_b;
            unsigned_bigint hi_c = hi_a * hi_b;

            bool neg = true;
            unsigned_bigint md_a;
            if (hi_a >= lo_a) md_a = hi_a - lo_a;
            else              md_a = lo_a - hi_a, neg = not neg;
            unsigned_bigint md_b;
            if (hi_b >= lo_b) md_b = hi_b - lo_b;
            else              md_b = lo_b - hi_b, neg = not neg;
            unsigned_bigint md_ab = md_a * md_b;
            unsigned_bigint md_c = (hi_c << m) + lo_c + hi_c + lo_c._cut(m, lo_c.size());
            if (neg) md_c -= md_ab;
            else     md_c += md_ab;
            unsigned_bigint c = (md_c << m) + lo_c._cut(0, m);
            c._cut_leading_zeros();
            return c;
        }

        static unsigned_bigint _mul_fft(const unsigned_bigint& a, const unsigned_bigint& b) {
            if (std::min(a.size(), b.size()) <= 64) {
                return _mul_naive(a, b);
            }
            if (std::max(a.size(), b.size()) <= 200) {
                return _mul_karatsuba(a, b);
            }
            return _build(suisen::convolution_int(a, b));
        }

        // compare(a, D^k)
        static int _compare_powD(const unsigned_bigint& a, int k) {
            const int dA = a.size();
            if (dA <= k) return -1;
            if (dA >= k + 2) return +1;
            if (a[k] != 1) return +1;
            for (int i = 0; i < k; ++i) {
                if (a[i]) return +1;
            }
            return 0;
        }
        static unsigned_bigint _powD(int k) {
            return ONE << k;
        }

        static std::pair<unsigned_bigint, unsigned_bigint> _divmod_int(const unsigned_bigint& a, const unsigned_bigint& b) {
            assert(b.size() == 1);
            const int b0 = b.front();
            unsigned_bigint q;
            long long r = 0;
            for (auto it = a.rbegin(); it != a.rend(); ++it) {
                r = r * D + *it;
                q.push_back(r / b0);
                r %= b0;
            }
            std::reverse(q.begin(), q.end());
            q._cut_leading_zeros();
            return { q, r ? unsigned_bigint{ int(r) } : ZERO };
        }

        static std::pair<unsigned_bigint, unsigned_bigint> _divmod_naive(unsigned_bigint& a, unsigned_bigint& b) {
            if (b.size() == 1) {
                return _divmod_int(a, b);
            }
            if (a < b) {
                return { ZERO, a };
            }
            const unsigned_bigint coef{ D / (b.back() + 1) };
            a *= coef;
            b *= coef;
            assert(2 * b.back() >= D);

            unsigned_bigint q, r(a.end() - b.size(), a.end());
            for (int i = a.size() - b.size(); i >= 0; --i) {
                if (r.size() < b.size()) {
                    q.push_back(0);
                } else if (r.size() == b.size()) {
                    if (r >= b) {
                        q.push_back(1);
                        r -= b;
                    } else {
                        q.push_back(0);
                    }
                } else {
                    assert(r.size() == b.size() + 1);
                    int x = (static_cast<long long>(r.end()[-1]) * D + r.end()[-2]) / b.back();
                    unsigned_bigint bx = b * unsigned_bigint{ x };
                    while (bx > r) bx -= b, --x;
                    while (bx + b <= r) bx += b, ++x;
                    q.push_back(x);
                    r = r - bx;
                }
                if (i) {
                    r.insert(r.begin(), a[i - 1]);
                }
            }
            std::reverse(q.begin(), q.end());
            q._cut_leading_zeros();
            r._cut_leading_zeros();
            return { q, _divmod_int(r, coef).first };
        }
        static std::pair<unsigned_bigint, unsigned_bigint> _divmod_naive(const unsigned_bigint& a, const unsigned_bigint& b) {
            unsigned_bigint a_ = a, b_ = b;
            return _divmod_naive(a_, b_);
        }

        // floor(D^n/b)
        static unsigned_bigint _div_powD(int n, unsigned_bigint b) {
            assert(b.size() and 2 * b.back() >= D);

            const int dB = b.size();

            int k = n - dB;
            while (k > 64) k = (k + 1) >> 1;
            k = std::min(n, dB + k);

            unsigned_bigint c = _divmod_naive(_powD(k), b).first;
            unsigned_bigint bc = b * c;
            for (; k < n; k = 2 * k - dB) {
                // loop invariant: c = floor(D^k/B)
                bc.resize(k + 1);
                int carry = 0;
                for (int i = 0; i < k; ++i) {
                    bc[i] = D - bc[i] + (i ? carry - 1 : 0);
                    if (bc[i] >= D) {
                        bc[i] -= D;
                        carry = 1;
                    } else {
                        carry = 0;
                    }
                }
                ++bc[k];
                c *= bc;
                c.erase(c.begin(), c.begin() + dB);
                bc = b * c;
                if (_compare_powD(bc + b, 2 * k - dB) <= 0) {
                    ++c, bc += b;
                }
                assert(_compare_powD(bc + b, 2 * k - dB) > 0);
            }
            // c = floor(D^k/b)
            c >>= k - n;
            return c;
        }

        static std::pair<unsigned_bigint, unsigned_bigint> _divmod(unsigned_bigint a, unsigned_bigint b) {
            assert(b.size());
            if (std::min(static_cast<int>(b.size()), static_cast<int>(a.size()) - static_cast<int>(b.size())) <= 64) {
                return _divmod_naive(a, b);
            }
            if (a < b) {
                return { ZERO, a };
            }

            const unsigned_bigint coef{ D / (b.back() + 1) };
            a *= coef;
            b *= coef;
            assert(2 * b.back() >= D);

            const int dA = a.size(), dB = b.size();
            if (dA == dB) {
                return { ONE, _divmod_int(a - b, coef).first };
            }
            unsigned_bigint invB = _div_powD(dA, b);
            unsigned_bigint q = a * invB;
            q.erase(q.begin(), q.begin() + dA);
            unsigned_bigint qb = q * b, qb2 = qb + b;
            if (qb2 <= a) {
                return { ++q, _divmod_int(a - qb2, coef).first };
            } else {
                return { q, _divmod_int(a - qb, coef).first };
            }
        }

        std::string _to_string() const {
            if (this->empty()) return "0";
            std::ostringstream oss;
            auto it = this->rbegin();
            oss << *it;
            while (++it != this->rend()) {
                oss << std::setw(9) << std::setfill('0') << *it;
            }
            return oss.str();
        }
    };
} // namespace suisen



#line 5 "library/math/bigint.hpp"

namespace suisen {
    struct bigint {
        static inline struct { operator bigint() const { return bigint{ unsigned_bigint::ZERO }; }; } const ZERO{};
        static inline struct { operator bigint() const { return bigint{ unsigned_bigint::ONE }; }; } const ONE{};

        bigint() : _neg(false), _dat{} {}

        template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>
        bigint(T v) {
            _neg = false;
            if constexpr (std::is_signed_v<T>) {
                if (v < 0) {
                    _neg = true;
                    v = -v;
                }
            }
            _dat = unsigned_bigint(v);
        }
        bigint(const std::string& s) {
            if (s.front() == '-') {
                _neg = true;
                _dat = unsigned_bigint(s.substr(1));
                fix_sign();
            } else {
                _neg = false;
                _dat = unsigned_bigint(s);
            }
        }
        bigint(const char* s) : bigint(std::string(s)) {}

        bigint(const unsigned_bigint& dat) : _neg(false), _dat(dat) {}
        bigint(unsigned_bigint&& dat) : _neg(false), _dat(std::move(dat)) {}

        operator bool() const {
            return bool(_dat);
        }

        friend bool operator==(const bigint& a, const bigint& b) {
            if (a._neg xor b._neg) {
                return false;
            } else {
                return a._dat == b._dat;
            }
        }
        friend bool operator!=(const bigint& a, const bigint& b) {
            return not (a == b);
        }

        friend bool operator<(const bigint& a, const bigint& b) {
            if (a._neg xor b._neg) {
                return a._neg;
            } else if (a._neg) {
                return a._dat > b._dat;
            } else {
                return a._dat < b._dat;
            }
        }
        friend bool operator<=(const bigint& a, const bigint& b) {
            return not (b < a);
        }
        friend bool operator>(const bigint& a, const bigint& b) {
            return b < a;
        }
        friend bool operator>=(const bigint& a, const bigint& b) {
            return not (a < b);
        }

        friend bigint& operator<<=(bigint& a, int shamt) {
            a._dat <<= shamt;
            return a;
        }
        friend bigint operator<<(bigint a, int shamt) {
            a <<= shamt;
            return a;
        }
        friend bigint& operator>>=(bigint& a, int shamt) {
            a._dat >>= shamt;
            a.fix_sign();
            return a;
        }
        friend bigint operator>>(bigint a, int shamt) {
            a >>= shamt;
            a.fix_sign();
            return a;
        }

        bigint operator+() const {
            return *this;
        }
        bigint operator-() const {
            return bigint(_dat, not _neg);
        }

        bigint& operator++() {
            if (_neg) {
                --_dat;
                fix_sign();
            } else {
                ++_dat;
            }
            return *this;
        }
        bigint operator++(int) {
            bigint res = *this;
            ++*this;
            return res;
        }
        bigint& operator--() {
            if (_neg) {
                ++_dat;
            } else if (_dat) {
                --_dat;
            } else {
                _neg = true;
                _dat = unsigned_bigint::ONE;
            }
            return *this;
        }
        bigint operator--(int) {
            bigint res = *this;
            --*this;
            return res;
        }
        friend bigint& operator+=(bigint& a, const bigint& b) {
            if (a._neg xor b._neg) {
                if (a._dat >= b._dat) {
                    a._dat -= b._dat;
                } else {
                    a._dat = b._dat - a._dat;
                    a._neg = not a._neg;
                }
                a.fix_sign();
            } else {
                a._dat += b._dat;
            }
            return a;
        }
        friend bigint operator+(const bigint& a, const bigint& b) {
            bigint c = a;
            c += b;
            return c;
        }
        friend bigint& operator-=(bigint& a, const bigint& b) {
            if (a._neg xor b._neg) {
                a._dat += b._dat;
            } else {
                if (a._dat >= b._dat) {
                    a._dat -= b._dat;
                } else {
                    a._dat = b._dat - a._dat;
                    a._neg = not a._neg;
                }
                a.fix_sign();
            }
            return a;
        }
        friend bigint operator-(const bigint& a, const bigint& b) {
            bigint c = a;
            c -= b;
            return c;
        }
        friend bigint& operator*=(bigint& a, const bigint& b) {
            return a = a * b;
        }
        friend bigint operator*(const bigint& a, const bigint& b) {
            return bigint(a._dat * b._dat, a._neg xor b._neg);
        }

        static std::pair<bigint, bigint> divmod(bigint a, bigint b) {
            auto [q, r] = unsigned_bigint::divmod(a._dat, b._dat);
            return { bigint(std::move(q), a._neg xor b._neg), bigint(std::move(r), a._neg) };
        }
        friend bigint& operator/=(bigint& a, const bigint& b) {
            return a = a / b;
        }
        friend bigint operator/(const bigint& a, const bigint& b) {
            return divmod(a, b).first;
        }
        friend bigint& operator%=(bigint& a, const bigint& b) {
            return a = a % b;
        }
        friend bigint operator%(const bigint& a, const bigint& b) {
            return divmod(a, b).second;
        }

#define CAST_PRIMITIVE(type)                \
        operator type() const {             \
            type res = _dat;                \
            return _neg ? -res : res;       \
        }                                   \

        CAST_PRIMITIVE(unsigned int)
        CAST_PRIMITIVE(unsigned long)
        CAST_PRIMITIVE(unsigned long long)
        CAST_PRIMITIVE(__uint128_t)
        CAST_PRIMITIVE(float)
        CAST_PRIMITIVE(double)
        CAST_PRIMITIVE(long double)
#undef CAST_PRIMITIVE

#define CAST_SIGNED_INT(type)                                       \
        operator type() const {                                     \
            return static_cast<std::make_unsigned_t<type>>(*this);  \
        }                                                           \

        CAST_SIGNED_INT(int)
        CAST_SIGNED_INT(long)
        CAST_SIGNED_INT(long long)
#undef CAST_SIGNED_INT

        operator __int128_t() const {
            return static_cast<__uint128_t>(*this);
        }

        operator unsigned_bigint() const {
            assert(not _neg);
            return _dat;
        }

        operator std::string() const {
            if (_neg) {
                return '-' + std::string(_dat);
            } else {
                return std::string(_dat);
            }
        }

        friend std::istream& operator>>(std::istream& in, bigint& v) {
            std::string s;
            in >> s, v = s;
            return in;
        }
        friend std::ostream& operator<<(std::ostream& out, const bigint& v) {
            return out << std::string(v);
        }
    private:
        bigint(const unsigned_bigint& dat, bool neg) : _neg(neg), _dat(dat) { fix_sign(); }
        bigint(unsigned_bigint&& dat, bool neg) : _neg(neg), _dat(std::move(dat)) { fix_sign(); }

        bool _neg;
        unsigned_bigint _dat;

        void fix_sign() {
            if (_neg and not _dat) _neg = false;
        }
    };
} // namespace suisen



#line 6 "test/src/math/bigint/NTL_2_A.test.cpp"
using suisen::bigint;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    bigint a, b;
    std::cin >> a >> b;
    std::cout << a + b << std::endl;
    return 0;
}
Back to top page