--- tags: codebook --- # infinite_int {%hackmd theme-dark %} ```cpp= //#pragma once #include<iostream> #include<iomanip> #include<vector> #include<cmath> #include<cassert> #include<algorithm> using namespace std; //#define NDEBUG static constexpr unsigned limit = 1000000000; class infinite_int { private: int m_sgn; vector<unsigned> m_data; //輔助函數 friend bool uless (const infinite_int& a, const infinite_int& b);// friend bool ugreater(const infinite_int& a, const infinite_int& b);// friend const infinite_int& umax(const infinite_int& a, const infinite_int& b);// friend const infinite_int& umin(const infinite_int& a, const infinite_int& b);// infinite_int& shrink();// infinite_int& lshift(unsigned x); infinite_int& rshift(unsigned x); friend infinite_int karatsuba(infinite_int a, infinite_int b); public: //建構元 infinite_int(const long long& x);// infinite_int(string str);// infinite_int(const infinite_int& x);// //解構元 ~infinite_int();// //串流運算子 friend ostream& operator<<(ostream& os, const infinite_int& x);// friend istream& operator>>(istream& is, infinite_int& x);// //算數運算子 friend infinite_int operator-(infinite_int a);// friend const infinite_int& operator+(const infinite_int& a);// friend infinite_int operator+(const infinite_int& a, const infinite_int& b);// friend infinite_int operator-(const infinite_int& a, const infinite_int& b);// friend infinite_int operator*(const infinite_int& a, const infinite_int& b); friend infinite_int operator/(const infinite_int& a, const infinite_int& b); friend infinite_int& operator+=(infinite_int& a, const infinite_int& b);// friend infinite_int& operator-=(infinite_int& a, const infinite_int& b);// friend infinite_int& operator*=(infinite_int& a, const infinite_int& b); friend infinite_int& operator/=(infinite_int& a, const infinite_int& b); //位元運算子 friend infinite_int operator&(const infinite_int& a, const infinite_int& b); friend infinite_int operator|(const infinite_int& a, const infinite_int& b); friend infinite_int operator^(const infinite_int& a, const infinite_int& b); friend infinite_int operator<<(const infinite_int& a, const unsigned& b); friend infinite_int operator>>(const infinite_int& a, const unsigned& b); friend infinite_int& operator&=(infinite_int& a, const infinite_int& b); friend infinite_int& operator|=(infinite_int& a, const infinite_int& b); friend infinite_int& operator^=(infinite_int& a, const infinite_int& b); friend infinite_int& operator<<=(infinite_int& a, const unsigned& b); friend infinite_int& operator>>=(infinite_int& a, const unsigned& b); //比較運算子 friend bool operator==(const infinite_int& a, const infinite_int& b);// friend bool operator!=(const infinite_int& a, const infinite_int& b);// friend bool operator< (const infinite_int& a, const infinite_int& b);// friend bool operator<=(const infinite_int& a, const infinite_int& b);// friend bool operator> (const infinite_int& a, const infinite_int& b);// friend bool operator>=(const infinite_int& a, const infinite_int& b);// }; bool uless(const infinite_int& a, const infinite_int& b) { if (a.m_data.size() != b.m_data.size()) return a.m_data.size() < b.m_data.size(); for (size_t i = a.m_data.size(); i; i--) if (a.m_data.at(i - 1) != b.m_data.at(i - 1)) return a.m_data.at(i - 1) < b.m_data.at(i - 1); return false; } bool ugreater(const infinite_int& a, const infinite_int& b) { if (a.m_data.size() != b.m_data.size()) return a.m_data.size() > b.m_data.size(); for (size_t i = a.m_data.size(); i; i--) if (a.m_data.at(i - 1) != b.m_data.at(i - 1)) return a.m_data.at(i - 1) > b.m_data.at(i - 1); return false; } const infinite_int& umax(const infinite_int& a, const infinite_int& b) { return uless(a, b) ? b : a; } const infinite_int& umin(const infinite_int& a, const infinite_int& b) { return uless(a, b) ? a : b; } infinite_int& infinite_int::shrink() { while (m_data.size() > 1 && !m_data.back()) m_data.pop_back(); if (m_data.size() && !m_data.back()) m_sgn = 0; return *this; } infinite_int& infinite_int::lshift(unsigned x) { size_t size = m_data.size(); m_data.resize(size + x, 0); for (size_t i = size; i; i--) m_data.at(x + i - 1) = m_data.at(i - 1); return shrink(); } infinite_int& infinite_int::rshift(unsigned x) { if (x >= m_data.size()) return *this = 0; for (size_t i = 0; i != m_data.size() - x; i++) m_data.at(i) = m_data.at(i + x); m_data.resize(m_data.size() - x); return shrink(); } infinite_int karatsuba(infinite_int a, infinite_int b) { a.shrink(), b.shrink(); // cout << "original a: " << a << endl; // cout << "original b: " << b << endl; if (min(a.m_data.size(), b.m_data.size()) <= 32) { infinite_int ret = 0; long long tmp = 0; ret.m_data.resize(a.m_data.size() + b.m_data.size() + 1, 0); for (size_t i = 0; i != a.m_data.size(); i++) { for (size_t j = 0; j != b.m_data.size(); j++) tmp += static_cast<long long>(a.m_data.at(i)) * b.m_data.at(j) + ret.m_data.at(i + j), ret.m_data.at(i + j) = tmp % limit, tmp /= limit; ret.m_data.at(i + b.m_data.size()) += tmp, tmp = 0; } ret.m_sgn = a.m_sgn * b.m_sgn; // cout << "O(n^2): " << ret.shrink() << endl; return ret.shrink(); } size_t m = min(a.m_data.size(), b.m_data.size()) / 2; infinite_int ap = a, bp = b; a.rshift(m), b.rshift(m); ap.m_data.resize(m), bp.m_data.resize(m); ap.shrink(), bp.shrink(); // cout << "a: " << a << endl << "b: " << b << endl; // cout << "ap: " << ap << endl << "bp: " << bp << endl; infinite_int z0 = karatsuba(ap, bp); infinite_int z1 = karatsuba(a + ap, b + bp); infinite_int z2 = karatsuba(a, b); // cout << "z0: " << z0 << endl << "z1: " << z1 << endl << "z2: " << z2 << endl; z0 += (z2.lshift(m) + z1 - z2 - z0).lshift(m); return z0.shrink(); } unsigned _abs(long long x) { return x >= 0 ? x : -x; } infinite_int::infinite_int(const long long& x = 0): m_sgn(x ? (x > 0 ? 1 : -1) : 0), m_data{_abs(x % limit), _abs(x / limit)} {shrink();} infinite_int::infinite_int(string str) { m_sgn = 1; if (str.front() == '-') m_sgn = -1, str = str.substr(1); while (str.size() >= 9) m_data.push_back(atoi(str.substr(str.size() - 9).data())), str.resize(str.size() - 9); if (str.size()) m_data.push_back(atoi(str.data())); shrink(); } infinite_int::infinite_int(const infinite_int& x): m_sgn(x.m_sgn), m_data(x.m_data) {shrink();} infinite_int::~infinite_int() {} ostream& operator<<(ostream& os, const infinite_int& x) { os << (x.m_sgn == -1 ? "-" : "") << x.m_data.back(); for (auto i = next(x.m_data.crbegin()); i != x.m_data.crend(); i++) os << setfill('0') << setw(9) << *i; return os; } istream& operator>>(istream& is, infinite_int& x) { string str; is >> str; x = infinite_int(str); return is; } infinite_int operator-(infinite_int a) { a.m_sgn *= -1; return a; } const infinite_int& operator+(const infinite_int& a) { return a; } infinite_int operator+(const infinite_int& a, const infinite_int& b) { if (!a.m_sgn || !b.m_sgn) return a.m_sgn ? a : b; const infinite_int& refa = umin(a, b); const infinite_int& refb = umax(a, b); assert(refa.m_data.size() <= refb.m_data.size()); infinite_int c; c.m_data.resize(refb.m_data.size() + 1, 0); long long tmp = 0; if (a.m_sgn * b.m_sgn == 1) { for (size_t i = 0; i < refa.m_data.size(); i++) assert(i < refa.m_data.size()), assert(i < refb.m_data.size()), tmp += refa.m_data.at(i) + refb.m_data.at(i), c.m_data.at(i) = tmp % limit, tmp /= limit; for (size_t i = refa.m_data.size(); i < refb.m_data.size(); i++) assert(i < refb.m_data.size()), tmp += refb.m_data.at(i), c.m_data.at(i) = tmp % limit, tmp /= limit; } else { for (size_t i = 0; i < refa.m_data.size(); i++) assert(i < refa.m_data.size()), assert(i < refb.m_data.size()), tmp += static_cast<long long>(limit) + refb.m_data.at(i), tmp -= refa.m_data.at(i), c.m_data.at(i) = tmp % limit, tmp /= limit, tmp--; for (size_t i = refa.m_data.size(); i < refb.m_data.size(); i++) assert(i < refb.m_data.size()), tmp += limit + refb.m_data.at(i), c.m_data.at(i) = tmp % limit, tmp /= limit, tmp--; } c.m_data.back() = tmp, c.m_sgn = refb.m_sgn; return c.shrink(); } infinite_int& operator+=(infinite_int& a, const infinite_int& b) { if (!a.m_sgn) {a = b; return a.shrink();} if (!b.m_sgn) {return a.shrink();} a.m_data.resize(max(a.m_data.size(), b.m_data.size()) + 1, 0); long long tmp = 0; if (a.m_sgn * b.m_sgn == 1) { for (size_t i = 0; i < b.m_data.size(); i++) assert(i < a.m_data.size()), assert(i < b.m_data.size()), tmp += a.m_data.at(i) + b.m_data.at(i), a.m_data.at(i) = tmp % limit, tmp /= limit; } else { if (uless(a, b)) { for (size_t i = 0; i < b.m_data.size(); i++) assert(i < a.m_data.size()), assert(i < b.m_data.size()), tmp += static_cast<long long>(limit) + b.m_data.at(i) - a.m_data.at(i), a.m_data.at(i) = tmp % limit, tmp /= limit, tmp--; a.m_sgn = b.m_sgn; } else { for (size_t i = 0; i < b.m_data.size(); i++) assert(i < a.m_data.size()), assert(i < b.m_data.size()), tmp += static_cast<long long>(limit) + a.m_data.at(i) - b.m_data.at(i), a.m_data.at(i) = tmp % limit, tmp /= limit, tmp--; } } a.m_data.at(b.m_data.size()) = tmp; return a.shrink(); } infinite_int operator-(const infinite_int& a, const infinite_int& b) { if (!a.m_sgn || !b.m_sgn) return a.m_sgn ? a : b; const infinite_int& refa = umin(a, b); const infinite_int& refb = umax(a, b); assert(refa.m_data.size() <= refb.m_data.size()); infinite_int c; c.m_data.resize(refb.m_data.size() + 1, 0); long long tmp = 0; if (a.m_sgn * -b.m_sgn == 1) { for (size_t i = 0; i < refa.m_data.size(); i++) assert(i < refa.m_data.size()), assert(i < refb.m_data.size()), tmp += refa.m_data.at(i) + refb.m_data.at(i), c.m_data.at(i) = tmp % limit, tmp /= limit; for (size_t i = refa.m_data.size(); i < refb.m_data.size(); i++) assert(i < refb.m_data.size()), tmp += refb.m_data.at(i), c.m_data.at(i) = tmp % limit, tmp /= limit; } else { for (size_t i = 0; i < refa.m_data.size(); i++) assert(i < refa.m_data.size()), assert(i < refb.m_data.size()), tmp += static_cast<long long>(limit) + refb.m_data.at(i) - refa.m_data.at(i), c.m_data.at(i) = tmp % limit, tmp /= limit, tmp--; for (size_t i = refa.m_data.size(); i < refb.m_data.size(); i++) assert(i < refb.m_data.size()), tmp += static_cast<long long>(limit) + refb.m_data.at(i), c.m_data.at(i) = tmp % limit, tmp /= limit, tmp--; } c.m_data.back() = tmp, c.m_sgn = &a == &refb ? refb.m_sgn : refb.m_sgn * -1; return c.shrink(); } infinite_int& operator-=(infinite_int& a, const infinite_int& b) { if (!a.m_sgn) {a = b, a.m_sgn = -1; return a.shrink();} if (!b.m_sgn) {return a.shrink();} a.m_data.resize(max(a.m_data.size(), b.m_data.size()) + 1, 0); long long tmp = 0; if (a.m_sgn * -b.m_sgn == 1) { for (size_t i = 0; i < b.m_data.size(); i++) assert(i < a.m_data.size()), assert(i < b.m_data.size()), tmp += a.m_data.at(i) + b.m_data.at(i), a.m_data.at(i) = tmp % limit, tmp /= limit; } else { if (uless(a, b)) { for (size_t i = 0; i < b.m_data.size(); i++) assert(i < a.m_data.size()), assert(i < b.m_data.size()), tmp += limit + b.m_data.at(i) - a.m_data.at(i), a.m_data.at(i) = tmp % limit, tmp /= limit, tmp--; a.m_sgn = -b.m_sgn; } else { for (size_t i = 0; i < b.m_data.size(); i++) assert(i < a.m_data.size()), assert(i < b.m_data.size()), tmp += limit + a.m_data.at(i) - b.m_data.at(i), a.m_data.at(i) = tmp % limit, tmp /= limit, tmp--; } } a.m_data.at(b.m_data.size()) = tmp; return a.shrink(); } infinite_int operator*(const infinite_int& a, const infinite_int& b) {return karatsuba(a, b);} infinite_int& operator*=(infinite_int& a, const infinite_int& b) {return a = a * b;} bool operator< (const infinite_int& a, const infinite_int& b) { return a.m_sgn != b.m_sgn ? a.m_sgn < b.m_sgn : uless(a, b) ^ (a.m_sgn == -1); } bool operator<=(const infinite_int& a, const infinite_int& b) { return a.m_sgn != b.m_sgn ? a.m_sgn <= b.m_sgn : !ugreater(a, b) ^ (a.m_sgn == -1); } bool operator> (const infinite_int& a, const infinite_int&b) { return a.m_sgn != b.m_sgn ? a.m_sgn > b.m_sgn : ugreater(a, b) ^ (a.m_sgn == -1); } bool operator>=(const infinite_int& a, const infinite_int&b) { return a.m_sgn != b.m_sgn ? a.m_sgn >= b.m_sgn : !uless(a, b) ^ (a.m_sgn == -1); } bool operator==(const infinite_int& a, const infinite_int& b) { if (a.m_sgn != b.m_sgn || a.m_data.size() != b.m_data.size()) return false; for (size_t i = 0; i != a.m_data.size(); i++) if (a.m_data[i] != b.m_data[i]) return false; return true; } bool operator!=(const infinite_int& a, const infinite_int& b) { if (a.m_sgn != b.m_sgn || a.m_data.size() != b.m_data.size()) return true; for (size_t i = 0; i != a.m_data.size(); i++) if (a.m_data[i] != b.m_data[i]) return true; return false; } infinite_int pow(infinite_int a, unsigned long long b) { infinite_int ret = 1; for (; b; b >>= 1, a *= a) if (b & 1) ret *= a; return ret; } int main() { infinite_int a; unsigned long long b; while (cin >> a >> b) cout << pow(a, b) << endl; return 0; } ```