#include #include #include #include #include #include namespace FastFourierTransform { typedef double ld; typedef std::complex cld; typedef std::vector ComplexPolynom; const ld PI = acosl(-1); std::vector Muliplication(const std::vector& a, const std::vector& b, std::vector& result); ComplexPolynom ToComplex(const std::vector& a); void FastFourierTransform_(ComplexPolynom& a, bool invert); std::vector Muliplication(const std::vector& a, const std::vector& b, std::vector& result) { ComplexPolynom ca = ToComplex(a); ComplexPolynom cb = ToComplex(b); size_t n = std::max(a.size(), b.size()); size_t m = 1; while (m < n) m <<= 1; m <<= 1; ca.resize(m); cb.resize(m); FastFourierTransform_(ca, false); FastFourierTransform_(cb, false); for (size_t i = 0; i < m; ++i) { ca[i] *= cb[i]; } FastFourierTransform_(ca, true); std::vector v(m); for (size_t i = 0; i < m; ++i) { v[i] = ca[i].real() + 0.5; } for (size_t i = 0; i < m; ++i) { v[i + 1] += v[i] / 10000; v[i] %= 10000; while (v[i] < 0) v[i] += 10000, v[i + 1] -= 1; } result.resize(v.size()); std::copy(v.begin(), v.end(), result.begin()); return result; } ComplexPolynom ToComplex(const std::vector& a) { ComplexPolynom res(a.begin(), a.end()); return res; } size_t rev(size_t num, size_t lg_n) { int res = 0; for (size_t i = 0; i < lg_n; ++i) if (num & (1 << i)) res |= 1 << (lg_n - 1 - i); return res; } void FastFourierTransform_(ComplexPolynom& a, bool invert) { size_t n = a.size(); size_t lg_n = 0; while ((1u << lg_n) < n) ++lg_n; for (size_t i = 0; i < n; ++i) if (i < rev(i, lg_n)) swap(a[i], a[rev(i, lg_n)]); for (size_t len = 2; len <= n; len <<= 1) { double ang = 2 * PI / len * (invert ? -1 : 1); cld wlen(cos(ang), sin(ang)); for (size_t i = 0; i < n; i += len) { cld w(1); for (size_t j = 0; j < len / 2; ++j) { cld u = a[i + j], v = a[i + j + len / 2] * w; a[i + j] = u + v; a[i + j + len / 2] = u - v; w *= wlen; } } } if (invert) for (size_t i = 0; i < n; ++i) a[i] /= n; } }; class BigInteger; BigInteger operator-(const BigInteger& a, const BigInteger& b); BigInteger operator*(const BigInteger& a, const BigInteger& b); BigInteger operator/(const BigInteger& a, const BigInteger& b); BigInteger operator+(const BigInteger& a, const BigInteger& b); bool operator>(const BigInteger& a, const BigInteger& b); bool operator<=(const BigInteger& a, const BigInteger& b); bool operator>=(const BigInteger& a, const BigInteger& b); bool operator==(const BigInteger& a, const BigInteger& b); bool operator!=(const BigInteger& a, const BigInteger& b); BigInteger operator%(const BigInteger& a, const BigInteger& b); class BigInteger { public: BigInteger() {} BigInteger(int64_t x) { if (x < 0) { is_negative_ = true, x *= -1; } t_[0] = x % BASE; x /= BASE; while (x > 0) { t_.push_back(x % BASE); x /= BASE; } Normalize(); } BigInteger(const BigInteger& x) : t_(x.t_), is_negative_(x.is_negative_) {} void swap(BigInteger& x) { std::swap(t_, x.t_); std::swap(is_negative_, x.is_negative_); } BigInteger& operator=(const BigInteger& x) { BigInteger tmp = x; swap(tmp); return *this; } friend bool operator<(const BigInteger&a, const BigInteger& b) { if (a.is_negative_ ^ b.is_negative_) { return a.is_negative_; } if (a.t_.size() != b.t_.size()) { return (a.t_.size() < b.t_.size()) ^ a.is_negative_; } for (size_t i = a.t_.size(); i > 0; --i) { if (a.t_[i - 1] != b.t_[i - 1]) { return (a.t_[i - 1] < b.t_[i - 1]) ^ a.is_negative_; } } return a.is_negative_; } BigInteger& operator++() { *this += 1; Normalize(); return *this; } BigInteger operator++(int) { BigInteger tmp = *this; ++(*this); return tmp; } void addingDifferentSigns(const BigInteger& x) { int16_t carry[2] = {0, 0}; // Вычитаем, если *this < x, то последнее число будет отрицательным и // потом это пофиксим for (size_t i = 0; i < x.t_.size() || (carry[i & 1] && i < t_.size()); ++i) { if (i < x.t_.size()) { t_[i] -= x.t_[i]; } t_[i] += carry[i & 1]; if (t_[i] < 0 && i + 1 < t_.size()) { t_[i] += BASE; carry[(i & 1) ^ 1] = -1; } else { carry[(i & 1) ^ 1] = 0; } } // Убераем нули в начале и начинаем фиксить отрицательное число Normalize(); if (t_.back() < 0) { t_.pop_back(); for (size_t i = 0; i < t_.size(); ++i) { t_[i] = BASE - 1 - t_[i]; } ++t_[0]; while (t_.size() > 1 && t_.back() == 0) { t_.pop_back(); } is_negative_ ^= true; } // Когда мы пофиксили отрицательные числа, у нас в ячейках могли // образоваться числа >= BASE, фиксим это carry[0] = 0; carry[1] = 0; if (t_[0] >= BASE) { carry[1] = 1; t_[0] -= BASE; } for (size_t i = 1; i < t_.size() && carry[i & 1]; ++i) { t_[i] += carry[i & 1]; carry[i & 1] = 0; if (t_[i] >= BASE) { carry[(i & 1) ^ 1] = 1; t_[i] -= BASE; } } // У нас может произойти перенос в ячейку, которой не существует, добавим // ее) if (carry[t_.size() & 1]) { t_.push_back(1); } } BigInteger& operator+=(const BigInteger& x) { t_.resize(std::max(t_.size(), x.t_.size()) + 1); // Если числа одинаковых знаков - просто сложение if (!is_negative_ ^ x.is_negative_) { int16_t carry[2] = {0, 0}; for (size_t i = 0; i < x.t_.size() || carry[i & 1]; ++i) { if (i < x.t_.size()) { t_[i] += x.t_[i]; } t_[i] += carry[i & 1]; if (t_[i] >= BASE) { t_[i] -= BASE; carry[(i & 1) ^ 1] = 1; } else { carry[(i & 1) ^ 1] = 0; } } Normalize(); } else { addingDifferentSigns(x); } return *this; } BigInteger& operator-=(const BigInteger& x) { // a - b = -(-a + b) is_negative_ ^= 1; *this += x; is_negative_ ^= 1; Normalize(); return *this; } BigInteger& operator*=(int16_t x) { // Это умножение на маленькое число, работает за O(n) и используется в // делении if (x < 0) { is_negative_ = !is_negative_; x *= -1; } if (x >= BASE) { return *this *= BigInteger(x); } t_.resize(t_.size() + 3); int16_t carry[2] = {0, 0}; for (size_t i = 0; i < t_.size(); ++i) { carry[!(i & 1)] = (int(t_[i]) * x + carry[i & 1]) / BASE; t_[i] = (int(t_[i]) * x + carry[i & 1]) % BASE; } while (t_.size() > 1 && t_.back() == 0) t_.pop_back(); Normalize(); return *this; } BigInteger& operator*=(const BigInteger& x) { // Если число на которое нам надо умножить небольшое, выгоднее умножать за // квадрат if (x.t_.size() < 100) { return SquareMultiplication(x); } FastFourierTransform::Muliplication(t_, x.t_, t_); is_negative_ ^= x.is_negative_; Normalize(); return *this; } // Деление работает за O(N^2), мы вычисляем все значащие биты в делении, // которых O(n), с помощью бинпоиска(константа, так как log 10000), и // проверкой в бинпоиске за O(n), потому что используется умножение за O(n), и // в итоге O(N^2) BigInteger& operator/=(const BigInteger& x) { bool is_negative = is_negative_ ^ x.is_negative_; is_negative_ = false; std::vector res(t_.size() - std::min(x.t_.size(), t_.size()) + 4); int16_t d = 1; if (x < 0) { d = -1; } for (int i = res.size(); i > 0; --i) { int l = 0, r = BASE - 1, m; while (l != r) { m = (l + r + 1) / 2; if ((x * d * m).MuliplicationDegree10(i - 1) <= *this) { l = m; } else { r = m - 1; } } res[i - 1] = l; *this -= (x * d * res[i - 1]).MuliplicationDegree10(i - 1); } t_ = res; is_negative_ = is_negative; Normalize(); return *this; } BigInteger& operator%=(const BigInteger& x) { *this -= (*this / x) * x; Normalize(); return *this; } std::string toString() const { std::ostringstream string; if (is_negative_) { string << "-"; } string << t_.back(); for (auto it = ++t_.rbegin(); it != t_.rend(); ++it) { string << std::setw(4) << std::setfill('0') << *it; } return string.str(); } explicit operator bool() const { return t_.size() > 1 || t_[0]; } friend std::istream& operator>>(std::istream& in, BigInteger& x) { std::string s; in >> s; std::reverse(s.begin(), s.end()); if (s.back() == '-') { x.is_negative_ = true; s.pop_back(); } else { x.is_negative_ = false; } while (s.size() % 4) { s.push_back('0'); } x.t_.resize(s.size() / 4); for (size_t i = 0; i < s.size(); i += 4) { x.t_[i / 4] = s[i] - '0' + 10 * (s[i + 1] - '0') + 100 * (s[i + 2] - '0') + 1000 * (s[i + 3] - '0'); } x.Normalize(); return in; } friend std::ostream& operator<<(std::ostream& out, const BigInteger& x) { out << x.toString(); return out; } BigInteger operator-() { BigInteger tmp(*this); tmp.is_negative_ ^= true; tmp.Normalize(); return tmp; } private: void Normalize() { while (t_.size() > 1 && t_.back() == 0) { t_.pop_back(); } if (t_.size() == 1 && t_[0] == 0) { is_negative_ = false; } } // Это умножение на 10^degree BigInteger& MuliplicationDegree10(int degree) { size_t n = t_.size(); t_.resize(t_.size() + degree); std::rotate(t_.begin(), t_.begin() + n, t_.end()); Normalize(); return *this; } // Это используется, если число на которое мы умножаем не очень большое, потому что // FFT работает достаточно медленно BigInteger& SquareMultiplication(const BigInteger& x) { std::vector t(t_.size() + x.t_.size() + 1); for (size_t i = 0; i < t_.size(); ++i) { for (size_t j = 0; j < x.t_.size(); ++j) { t[i + j] += static_cast(t_[i]) * x.t_[j]; } } t_.resize(t_.size() + x.t_.size() + 1); for (size_t i = 0; i < t.size(); ++i) { t[i + 1] += t[i] / BASE; t_[i] = t[i] % BASE; } while (t_.size() > 1 && t_.back() == 0) t_.pop_back(); is_negative_ ^= x.is_negative_; Normalize(); return *this; } static constexpr uint16_t BASE = 10000; std::vector t_ = {0}; bool is_negative_ = false; }; BigInteger operator-(const BigInteger& a, const BigInteger& b) { return BigInteger(a) -= b; } BigInteger operator*(const BigInteger& a, const BigInteger& b) { return BigInteger(a) *= b; } BigInteger operator/(const BigInteger& a, const BigInteger& b) { BigInteger tmp(a); tmp /= b; return tmp; } BigInteger operator%(const BigInteger& a, const BigInteger& b) { BigInteger tmp(a); tmp %= b; return tmp; } BigInteger operator+(const BigInteger& a, const BigInteger& b) { return BigInteger(a) += b; } bool operator>(const BigInteger& a, const BigInteger& b) { return b < a; } bool operator<=(const BigInteger& a, const BigInteger& b) { return !(a > b); } bool operator>=(const BigInteger& a, const BigInteger& b) { return b <= a; } bool operator==(const BigInteger& a, const BigInteger& b) { return !(a < b) && !(b < a); } bool operator!=(const BigInteger& a, const BigInteger& b) { return !(a == b); } class Rational; Rational operator+(const Rational& a, const Rational& b); Rational operator-(const Rational& a, const Rational& b); Rational operator*(const Rational& a, const Rational& b); Rational operator/(const Rational& a, const Rational& b); bool operator>(const Rational& a, const Rational& b); bool operator<=(const Rational& a, const Rational& b); bool operator>=(const Rational& a, const Rational& b); bool operator==(const Rational& a, const Rational& b); bool operator!=(const Rational& a, const Rational& b); class Rational { public: Rational() = default; Rational(const BigInteger& a) { numerator_ = a; } Rational(int a) { numerator_ = a; } Rational(const Rational& x) : numerator_(x.numerator_), denominator_(x.denominator_) {} void swap(Rational& x) { std::swap(numerator_, x.numerator_); std::swap(denominator_, x.denominator_); } Rational& operator=(const Rational& x) { Rational tmp(x); swap(tmp); return *this; } Rational& operator+=(const Rational& a) { if (this == &a) { return *this += Rational(a); } numerator_ *= a.denominator_; numerator_ += a.numerator_ * denominator_; denominator_ *= a.denominator_; Normalize(); return *this; } Rational& operator-=(const Rational& a) { if (this == &a) { return *this -= Rational(a); } numerator_ *= a.denominator_; numerator_ -= a.numerator_ * denominator_; denominator_ *= a.denominator_; Normalize(); return *this; } Rational& operator*=(const Rational& a) { numerator_ *= a.numerator_; denominator_ *= a.denominator_; Normalize(); return *this; } Rational& operator/=(const Rational& a) { if (this == &a) { return *this /= Rational(a); } numerator_ *= a.denominator_; denominator_ *= a.numerator_; Normalize(); return *this; } Rational operator-() const { Rational tmp(*this); tmp.numerator_ *= -1; return tmp; } bool operator<(const Rational& a) const { return numerator_ * a.denominator_ < denominator_ * a.numerator_; } std::string toString() const { std::ostringstream str; str << numerator_; if (denominator_ != 1) { str << "/" << denominator_; } return str.str(); } std::string asDecimal(size_t precision) { BigInteger t = 1; for (size_t i = 0; i < precision; ++i) { t *= 10; } std::ostringstream str; BigInteger result = (numerator_ * t) / denominator_; if (result < 0) { str << "-", result *= -1; } str << result / t << "." << std::setw(precision) << std::setfill('0') << result % t; return str.str(); } explicit operator double() { return 1.0; } BigInteger gcd(const BigInteger& a, const BigInteger& b) { return b ? gcd(b, a % b) : a; } void Normalize() { if (numerator_ == 0) { denominator_ = 1; return; } BigInteger d = gcd(numerator_, denominator_); numerator_ /= d; denominator_ /= d; if (denominator_ < 0) { numerator_ *= -1; denominator_ *= -1; } } BigInteger numerator_ = 0; BigInteger denominator_ = 1; }; Rational operator+(const Rational& a, const Rational& b) { Rational tmp(a); tmp += b; return tmp; } Rational operator-(const Rational& a, const Rational& b) { Rational tmp(a); tmp -= b; return tmp; } Rational operator*(const Rational& a, const Rational& b) { Rational tmp(a); tmp *= b; return tmp; } Rational operator/(const Rational& a, const Rational& b) { Rational tmp(a); tmp /= b; return tmp; } bool operator>(const Rational& a, const Rational& b) { return b < a; } bool operator<=(const Rational& a, const Rational& b) { return a < b || a == b; } bool operator>=(const Rational& a, const Rational& b) { return a > b || a == b; } bool operator==(const Rational& a, const Rational& b) { return !(b < a) && !(a < b); } bool operator!=(const Rational& a, const Rational& b) { return !(a == b); }