Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma GCC optimize("O3")
- #include <algorithm>
- #include <ctime>
- #include <iostream>
- #include <random>
- #include <set>
- #include <utility>
- #include <vector>
- #define int ll
- using namespace std;
- const bool DEBUG = false;
- using ll = __int128;
- using uint128 = unsigned __int128;
- int CNT = 0;
- const int BASE = 1e18;
- const int x = 4294967296;
- const uint128 BASE2 = x * x;
- struct Number10 {
- bool negative = false;
- vector<int> digits;
- explicit Number10(int x) {
- if (x < BASE) {
- digits = {x};
- } else {
- while (x) {
- digits.push_back(x % BASE);
- x /= BASE;
- }
- }
- }
- explicit Number10(string str) {
- reverse(str.begin(), str.end());
- int value = 0;
- int cnt = 0;
- int multiplier = 1;
- for (auto& now: str) {
- if (cnt == 18) {
- digits.push_back(value);
- value = 0;
- multiplier = 1;
- cnt = 0;
- }
- ++cnt;
- value += multiplier * int(now - '0');
- multiplier *= 10;
- }
- digits.push_back(value);
- }
- explicit Number10(const vector<int>& value) {
- digits = value;
- }
- Number10& operator=(const Number10& other) = default;
- const int& operator[](size_t ind) const {
- return digits[ind];
- }
- size_t size() const {
- return digits.size();
- }
- Number10 shift(size_t cnt) const {
- vector<int> result(cnt);
- for (auto& now: digits) {
- result.push_back(now);
- }
- return Number10(result);
- }
- Number10 operator+(const Number10& other) const {
- if (other.negative) {
- return *this - (-other);
- }
- if (negative) {
- return other - (-*this);
- }
- vector<int> result(max(size(), other.size()));
- for (size_t i = 0; i < size(); ++i) {
- result[i] += digits[i];
- }
- for (size_t i = 0; i < other.size(); ++i) {
- result[i] += other[i];
- }
- for (size_t i = 0; i < result.size(); ++i) {
- if (result[i] >= BASE) {
- if (i + 1 == result.size()) {
- result.push_back(0);
- }
- result[i + 1] += result[i] / BASE;
- result[i] %= BASE;
- }
- }
- return Number10(result);
- }
- Number10 operator-() const {
- Number10 x(digits);
- x.negative = !negative;
- return x;
- }
- Number10 operator-(const Number10& other) const {
- if (other.negative) {
- return *this + (-other);
- }
- if (negative) {
- return -(other + (-*this));
- }
- if (*this >= other) {
- vector<int> result = digits;
- for (size_t i = 0; i < other.size(); ++i) {
- result[i] -= other[i];
- }
- for (size_t i = 0; i + 1 < result.size(); ++i) {
- if (result[i] < 0) {
- result[i] += BASE;
- result[i + 1] -= 1;
- }
- }
- while (result.size() > 1 && result.back() == 0) {
- result.pop_back();
- }
- return Number10(result);
- } else {
- Number10 result(other - *this);
- result.negative = true;
- return result;
- }
- }
- Number10& operator+=(const Number10& other) {
- return *this = *this + other;
- }
- Number10& operator-=(const Number10& other) {
- return *this = *this - other;
- }
- Number10 operator*(int value) const {
- vector<int> result(size());
- for (size_t i = 0; i < result.size(); ++i) {
- if (i < digits.size()) {
- result[i] += digits[i] * value;
- }
- if (result[i] >= BASE && i + 1 == result.size()) {
- result.push_back(0);
- }
- if (result[i] >= BASE) {
- result[i + 1] += result[i] / BASE;
- result[i] %= BASE;
- }
- }
- return Number10(result);
- }
- Number10 operator*(const Number10& other) const {
- Number10 result(string("0"));
- for (size_t i = 0; i < size(); ++i) {
- result += (other * digits[i]).shift(i);
- }
- result.negative = negative;
- if (other.negative) {
- result.negative = !result.negative;
- }
- return result;
- }
- Number10 operator*=(const Number10& other) {
- return *this = *this * other;
- }
- Number10 operator/(const Number10& other) const {
- Number10 number = *this;
- size_t cnt = number.size();
- vector<int> result(cnt);
- for (size_t i = cnt; i >= 1; --i) {
- auto it2 = other.shift(i - 1);
- int rhs = other.digits.back();
- int lhs = 0;
- if (other.size() + (i - 2) < number.size()) {
- lhs += number[other.size() + (i - 2)];
- }
- if (other.size() + (i - 1) < number.size()) {
- lhs += BASE * number[other.size() + (i - 1)];
- }
- int x = (lhs + 1) / rhs;
- for (; x >= 1;) {
- auto it = it2 * x;
- if (number >= it) {
- number -= it;
- result[i - 1] += x;
- }
- if (x == 1) {
- break;
- }
- int rhs = other.digits.back();
- int lhs = 0;
- if (other.size() + (i - 2) < number.size()) {
- lhs += number[other.size() + (i - 2)];
- }
- if (other.size() + (i - 1) < number.size()) {
- lhs += BASE * number[other.size() + (i - 1)];
- }
- x = min((x + 1) / 2, (lhs + 1) / rhs);
- }
- }
- while (result.size() > 1 && result.back() == 0) {
- result.pop_back();
- }
- return Number10(result);
- }
- Number10 operator%(const Number10& other) const {
- Number10 number = *this;
- size_t cnt = number.size();
- vector<int> result(cnt);
- for (size_t i = cnt; i >= 1; --i) {
- auto it2 = other.shift(i - 1);
- int rhs = other.digits.back();
- int lhs = 0;
- if (other.size() + (i - 2) < number.size()) {
- lhs += number[other.size() + (i - 2)];
- }
- if (other.size() + (i - 1) < number.size()) {
- lhs += BASE * number[other.size() + (i - 1)];
- }
- int x = (lhs + 1) / rhs;
- for (; x >= 1;) {
- auto it = it2 * x;
- if (number >= it) {
- number -= it;
- result[i - 1] += x;
- }
- if (x == 1) {
- break;
- }
- int rhs = other.digits.back();
- int lhs = 0;
- if (other.size() + (i - 2) < number.size()) {
- lhs += number[other.size() + (i - 2)];
- }
- if (other.size() + (i - 1) < number.size()) {
- lhs += BASE * number[other.size() + (i - 1)];
- }
- x = min((x + 1) / 2, (lhs + 1) / rhs);
- }
- }
- while (result.size() > 1 && result.back() == 0) {
- result.pop_back();
- }
- return number;
- }
- int operator%(int val) const {
- Number10 result = *this;
- int carry = 0;
- for (size_t i = result.size(); i >= 1; --i) {
- int cur = result[i - 1] + carry * 1ll * BASE;
- result.digits[i - 1] = int(cur / val);
- carry = int(cur % val);
- }
- return carry;
- }
- Number10 operator/(int val) const {
- Number10 result = *this;
- int carry = 0;
- for (size_t i = result.size(); i >= 1; --i) {
- int cur = result[i - 1] + carry * 1ll * BASE;
- result.digits[i - 1] = int(cur / val);
- carry = int(cur % val);
- }
- while (result.digits.size() > 1 && result.digits.back() == 0) {
- result.digits.pop_back();
- }
- return result;
- }
- bool operator<(const Number10& other) const {
- if (size() != other.size()) {
- return size() < other.size();
- }
- for (size_t i = size(); i >= 1; --i) {
- if (digits[i - 1] != other[i - 1]) {
- return digits[i - 1] < other[i - 1];
- }
- }
- return false;
- }
- bool operator>(const Number10& other) const {
- return (other < *this);
- }
- bool operator<=(const Number10& other) const {
- return !(*this > other);
- }
- bool operator>=(const Number10& other) const {
- return !(*this < other);
- }
- bool operator==(const Number10& other) const {
- return digits == other.digits;
- }
- bool operator!=(const Number10& other) const {
- return !(*this == other);
- }
- friend ostream& operator<<(ostream& out, const Number10& number) {
- bool good = false;
- if (number == Number10(0)) {
- return out << "0";
- }
- if (number.negative) {
- out << "-";
- }
- for (size_t i = number.size(); i >= 1; --i) {
- auto it = BASE / 10;
- while (it) {
- if (good || int32_t(number[i - 1] / it % 10)) {
- out << int32_t(number[i - 1] / it % 10);
- good = true;
- }
- it /= 10;
- }
- }
- return out;
- }
- };
- struct Number2 {
- bool negative = false;
- vector<uint128> digits;
- explicit Number2(uint128 x) {
- if (!(x >> 64)) {
- digits = {x};
- } else {
- while (x) {
- digits.push_back((uint64_t)x);
- x >>= 64;
- }
- }
- }
- explicit Number2(string str) {
- Number10 num10(str);
- vector<int> tmp;
- while (num10.digits.size() > 2 || num10.digits[0] > 0) {
- tmp.push_back(num10 % 2);
- num10 = num10 / 2;
- }
- int cnt = 0;
- int value = 0;
- int multiplier = 1;
- for (auto& now : tmp) {
- if (cnt == 64) {
- digits.push_back(value);
- cnt = 0;
- value = 0;
- multiplier = 1;
- }
- value += now * multiplier;
- multiplier <<= 1;
- ++cnt;
- }
- digits.push_back(value);
- }
- explicit Number2(const vector<uint128>& value) {
- digits = value;
- }
- Number2& operator=(const Number2& other) = default;
- const uint128& operator[](size_t ind) const {
- return digits[ind];
- }
- size_t size() const {
- return digits.size();
- }
- Number2 shift(size_t cnt) const {
- vector<uint128> result(cnt);
- for (auto& now: digits) {
- result.push_back(now);
- }
- return Number2(result);
- }
- Number2 operator+(const Number2& other) const {
- if (other.negative) {
- return *this - (-other);
- }
- if (negative) {
- return other - (-*this);
- }
- vector<uint128> result(max(size(), other.size()));
- for (size_t i = 0; i < size(); ++i) {
- result[i] += digits[i];
- }
- for (size_t i = 0; i < other.size(); ++i) {
- result[i] += other[i];
- }
- for (size_t i = 0; i < result.size(); ++i) {
- if (result[i] >> 64) {
- if (i + 1 == result.size()) {
- result.push_back(0);
- }
- result[i + 1] += (result[i] >> 64);
- result[i] = uint64_t(result[i]);
- }
- }
- return Number2(result);
- }
- Number2 operator-() const {
- Number2 x(digits);
- x.negative = !negative;
- return x;
- }
- Number2 operator-(const Number2& other) const {
- if (other.negative) {
- return *this + (-other);
- }
- if (negative) {
- return -(other + (-*this));
- }
- if (*this >= other) {
- vector<int> result;
- for (auto& now : digits) {
- result.push_back(now);
- }
- for (size_t i = 0; i < other.size(); ++i) {
- result[i] -= other[i];
- }
- for (size_t i = 0; i + 1 < result.size(); ++i) {
- if (result[i] < 0) {
- result[i] += BASE2;
- result[i + 1] -= 1;
- }
- }
- while (result.size() > 1 && result.back() == 0) {
- result.pop_back();
- }
- vector<uint128> hm;
- for (auto& now : result) {
- hm.push_back(now);
- }
- return Number2(hm);
- } else {
- Number2 result(other - *this);
- result.negative = true;
- return result;
- }
- }
- Number2& operator+=(const Number2& other) {
- return *this = *this + other;
- }
- Number2& operator-=(const Number2& other) {
- return *this = *this - other;
- }
- Number2 operator*(int value) const {
- vector<uint128> result(size());
- for (size_t i = 0; i < result.size(); ++i) {
- if (i < digits.size()) {
- result[i] += digits[i] * value;
- }
- if (result[i] >= BASE2 && i + 1 == result.size()) {
- result.push_back(0);
- }
- if (result[i] >= BASE2) {
- result[i + 1] += result[i] / BASE2;
- result[i] %= BASE2;
- }
- }
- return Number2(result);
- }
- Number2 operator*(const Number2& other) const {
- Number2 result(string("0"));
- for (size_t i = 0; i < size(); ++i) {
- result += (other * digits[i]).shift(i);
- }
- result.negative = negative;
- if (other.negative) {
- result.negative = !result.negative;
- }
- return result;
- }
- Number2 operator*=(const Number2& other) {
- return *this = *this * other;
- }
- Number2 operator/(const Number2& other) const {
- Number2 number = *this;
- size_t cnt = number.size();
- vector<uint128> result(cnt);
- for (size_t i = cnt; i >= 1; --i) {
- auto it2 = other.shift(i - 1);
- uint128 rhs = other.digits.back();
- uint128 lhs = 0;
- if (other.size() + (i - 2) < number.size()) {
- lhs += number[other.size() + (i - 2)];
- }
- if (other.size() + (i - 1) < number.size()) {
- lhs += BASE2 * number[other.size() + (i - 1)];
- }
- uint128 x = (lhs + 1) / rhs;
- for (; x >= 1;) {
- auto it = it2 * x;
- if (number >= it) {
- number -= it;
- result[i - 1] += x;
- }
- if (x == 1) {
- break;
- }
- uint128 rhs = other.digits.back();
- uint128 lhs = 0;
- if (other.size() + (i - 2) < number.size()) {
- lhs += number[other.size() + (i - 2)];
- }
- if (other.size() + (i - 1) < number.size()) {
- lhs += BASE2 * number[other.size() + (i - 1)];
- }
- x = min((x + 1) / 2, (lhs + 1) / rhs);
- }
- }
- while (result.size() > 1 && result.back() == 0) {
- result.pop_back();
- }
- return Number2(result);
- }
- Number2 operator%(const Number2& other) const {
- Number2 number = *this;
- size_t cnt = number.size();
- vector<int> result(cnt);
- for (size_t i = cnt; i >= 1; --i) {
- auto it2 = other.shift(i - 1);
- uint128 rhs = other.digits.back();
- uint128 lhs = 0;
- if (other.size() + (i - 2) < number.size()) {
- lhs += number[other.size() + (i - 2)];
- }
- if (other.size() + (i - 1) < number.size()) {
- lhs += BASE2 * number[other.size() + (i - 1)];
- }
- uint128 x = (lhs + 1) / rhs;
- for (; x >= 1;) {
- auto it = it2 * x;
- if (number >= it) {
- number -= it;
- result[i - 1] += x;
- }
- if (x == 1) {
- break;
- }
- uint128 rhs = other.digits.back();
- uint128 lhs = 0;
- if (other.size() + (i - 2) < number.size()) {
- lhs += number[other.size() + (i - 2)];
- }
- if (other.size() + (i - 1) < number.size()) {
- lhs += BASE2 * number[other.size() + (i - 1)];
- }
- x = min((x + 1) / 2, (lhs + 1) / rhs);
- }
- }
- while (result.size() > 1 && result.back() == 0) {
- result.pop_back();
- }
- return number;
- }
- int operator%(int val) const {
- Number2 result = *this;
- int carry = 0;
- for (size_t i = result.size(); i >= 1; --i) {
- int cur = result[i - 1] + carry * 1ll * BASE2;
- result.digits[i - 1] = int(cur / val);
- carry = int(cur % val);
- }
- return carry;
- }
- Number2 operator/(int val) const {
- Number2 result = *this;
- uint128 carry = 0;
- for (size_t i = result.size(); i >= 1; --i) {
- uint128 cur = result[i - 1] + carry * 1ll * BASE2;
- result.digits[i - 1] = uint128(cur / val);
- carry = uint128(cur % val);
- }
- while (result.digits.size() > 1 && result.digits.back() == 0) {
- result.digits.pop_back();
- }
- return result;
- }
- bool operator<(const Number2& other) const {
- if (size() != other.size()) {
- return size() < other.size();
- }
- for (size_t i = size(); i >= 1; --i) {
- if (digits[i - 1] != other[i - 1]) {
- return digits[i - 1] < other[i - 1];
- }
- }
- return false;
- }
- bool operator>(const Number2& other) const {
- return (other < *this);
- }
- bool operator<=(const Number2& other) const {
- return !(*this > other);
- }
- bool operator>=(const Number2& other) const {
- return !(*this < other);
- }
- bool operator==(const Number2& other) const {
- return digits == other.digits;
- }
- bool operator!=(const Number2& other) const {
- return !(*this == other);
- }
- friend ostream& operator<<(ostream& out, const Number2& number) {
- Number2 num = number;
- vector<int> tmp;
- while (num.digits.size() > 2 || num.digits[0] > 0) {
- tmp.push_back(num % 10);
- num = num / 10;
- }
- reverse(tmp.begin(), tmp.end());
- for (auto& now : tmp) {
- out << uint64_t(now);
- }
- return out;
- }
- };
- Number2 char_to_number(char symbol) {
- if (symbol >= 48 && symbol <= 57) {
- return Number2(symbol - 48);
- }
- if (symbol >= 65 && symbol <= 90) {
- return Number2(symbol - 55);
- }
- if (symbol >= 97 && symbol <= 122) {
- return Number2(symbol - 61);
- }
- if (symbol == 95) {
- return Number2(62);
- }
- if (symbol == 46) {
- return Number2(63);
- }
- throw runtime_error("Incorrect message");
- }
- pair<Number2, Number2> division(const Number2& a, const Number2& b) {
- Number2 number = a;
- size_t cnt = number.size();
- vector<uint128> result(cnt);
- for (size_t i = cnt; i >= 1; --i) {
- auto it2 = b.shift(i - 1);
- int rhs = b.digits.back();
- int lhs = 0;
- if (b.size() + (i - 2) < number.size()) {
- lhs += number[b.size() + (i - 2)];
- }
- if (b.size() + (i - 1) < number.size()) {
- lhs += BASE2 * number[b.size() + (i - 1)];
- }
- int x = (lhs + 1) / rhs;
- for (; x >= 1;) {
- auto it = it2 * x;
- if (number >= it) {
- number -= it;
- result[i - 1] += x;
- }
- if (x == 1) {
- break;
- }
- int rhs = b.digits.back();
- int lhs = 0;
- if (b.size() + (i - 2) < number.size()) {
- lhs += number[b.size() + (i - 2)];
- }
- if (b.size() + (i - 1) < number.size()) {
- lhs += BASE2 * number[b.size() + (i - 1)];
- }
- x = min((x + 1) / 2, (lhs + 1) / rhs);
- }
- }
- while (result.size() > 1 && result.back() == 0) {
- result.pop_back();
- }
- return {Number2(result), number};
- }
- const Number2 P(string("115792089210356248762697446949407573530086143415290314195533631308867097853951"));
- Number2 X(string("48439561293906451759052585252797914202762949526041747995844080717082404635286"));
- Number2 Y(string("36134250956749795798585127919587881956611106672985015071877198253568414405109"));
- Number2 ORD(string("115792089210356248762697446949407573529996955224135760342422259061068512044369"));
- Number2 gcd(const Number2& a, const Number2& b, Number2& x, Number2& y) {
- if (a == Number2(0)) {
- x = Number2(0);
- y = Number2(1);
- return b;
- }
- auto it = division(b, a);
- Number2 x1(0), y1(0);
- Number2 g = gcd(it.second, a, x1, y1);
- x = y1 - (it.first) * x1;
- y = x1;
- return g;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement