#include #include #include #include #include /* * TODO: assert and invert * порядок методов * проверка на N != M */ class BigInteger{ private: static const int BASE = 10; bool isPositive; //Zero is positive std::vector digits; void normilize(); void popBackZeros(); void fixMinusZero(); void reverseDigits(); void addDigit(short); friend std::istream& operator>>(std::istream&, BigInteger&); public: BigInteger(int); BigInteger(); BigInteger& operator+=(const BigInteger&); BigInteger operator+() const; BigInteger& operator++(); BigInteger operator++(int); BigInteger& operator-=(const BigInteger&); BigInteger operator-() const; BigInteger& operator--(); BigInteger operator--(int); BigInteger& operator*=(const BigInteger&); BigInteger& operator/=(const BigInteger&); BigInteger& operator%=(const BigInteger&); bool operator<(const BigInteger&) const; bool operator>(const BigInteger&) const; bool operator==(const BigInteger&) const; bool operator!=(const BigInteger&) const; bool operator<=(const BigInteger&) const; bool operator>=(const BigInteger&) const; explicit operator int() const; explicit operator bool() const; std::string toString() const; }; // if something weird in istream => return interpreted, istream is on the first weird symbol // also interpret number = sign as 0 std::istream& operator>>(std::istream& in, BigInteger& num) { char c; bool signDefined = false; num.isPositive = true; num.digits.clear(); while(in.get(c)) { if (c == '-' && !signDefined) { num.isPositive = false; signDefined = true; } else if (c == '+' && !signDefined) { num.isPositive = true; signDefined = true; } else if (c >= '0' && c <= '9') { num.digits.push_back(c - '0'); signDefined = true; } else { if (c != ' ' && c != '\n') in.putback(c); break; } } if (num.digits.size() == 0) num.digits.push_back(0); num.reverseDigits(); num.normilize(); return in; } std::ostream& operator<<(std::ostream& out, const BigInteger& num) { out << num.toString(); return out; } void BigInteger::normilize() { popBackZeros(); fixMinusZero(); } void BigInteger::popBackZeros() { while(digits.size() > 1 && digits.back() == 0) { digits.pop_back(); } } void BigInteger::fixMinusZero() { isPositive = !isPositive; if (*this == BigInteger(0)) isPositive = !isPositive; isPositive = !isPositive; } void BigInteger::reverseDigits() { int size = digits.size(); for (int i = 0; i < size / 2; ++i) { std::swap(digits[i], digits[size-1-i]); } } void BigInteger::addDigit(short digit) { reverseDigits(); digits.push_back(digit); reverseDigits(); } BigInteger::BigInteger(int value) { isPositive = (value >= 0); if (!isPositive) value = -value; if (!value) digits.push_back(0); while (value) { digits.push_back(value % BASE); value /= BASE; } } BigInteger::BigInteger() : BigInteger(0) { } BigInteger& BigInteger::operator+=(const BigInteger& num) { if (this == &num) { return *this += BigInteger(num); } if (num.isPositive == isPositive) { for (unsigned int i = 0; i < std::max(num.digits.size(), digits.size()); ++i) { short add = (i < num.digits.size() ? num.digits[i] : 0); if (digits.size() == i) digits.push_back(0); if (digits[i] + add >= BASE) { if (digits.size() == i + 1) digits.push_back(0); ++digits[i + 1]; } else if (i >= num.digits.size()) { digits[i] = (digits[i] + add) % BASE; break; } digits[i] = (digits[i] + add) % BASE; } } else { isPositive = !isPositive; *this -= num; isPositive = !isPositive; } normilize(); return *this; } BigInteger operator+(const BigInteger& num1, const BigInteger& num2) { BigInteger copy = num1; return copy += num2; } BigInteger BigInteger::operator+() const { return *this; } BigInteger& BigInteger::operator++() { return (*this += 1); } BigInteger BigInteger::operator++(int) { BigInteger copy = *this; ++(*this); return copy; } BigInteger& BigInteger::operator-=(const BigInteger& num) { if (this == &num) { return *this -= BigInteger(num); } if (num.isPositive == isPositive) { bool needChange = isPositive ^ (num <= *this); const BigInteger& a = needChange ? num : *this; const BigInteger& b = needChange ? *this : num; bool need = false; for (unsigned int i = 0; i < a.digits.size(); ++i) { bool needNext = (a.digits[i] - need - (i < b.digits.size() ? b.digits[i] : 0) < 0); if(i == digits.size()) digits.push_back(0); digits[i] = (a.digits[i] - need - (i < b.digits.size() ? b.digits[i] : 0) + BASE) % BASE; need = needNext; } isPositive ^= needChange; } else { isPositive = !isPositive; *this += num; isPositive = !isPositive; } normilize(); return *this; } BigInteger operator-(const BigInteger& num1, const BigInteger& num2) { BigInteger copy = num1; return copy -= num2; } BigInteger BigInteger::operator-() const { return BigInteger(0) -= *this; } BigInteger& BigInteger::operator--() { return (*this -= 1); } BigInteger BigInteger::operator--(int) { BigInteger copy = *this; --(*this); return copy; } BigInteger& BigInteger::operator*=(const BigInteger& num) { BigInteger ans; ans.digits.resize(digits.size() + num.digits.size()); for(unsigned int i = 0; i < digits.size(); ++i) { int add = 0; for (unsigned int j = 0; j <= num.digits.size(); ++j) { short numDigit = (j == num.digits.size() ? 0 : num.digits[j]); short addNext = (ans.digits[i + j] + digits[i] * numDigit + add) / BASE; ans.digits[i + j] = (ans.digits[i + j] + digits[i] * numDigit + add) % BASE; add = addNext; } } ans.isPositive = !(isPositive ^ num.isPositive); ans.normilize(); return *this = ans; } BigInteger operator*(const BigInteger& num1, const BigInteger& num2) { BigInteger copy = num1; return copy *= num2; } BigInteger& BigInteger::operator/=(const BigInteger& num) { if(num == 0) return *this; BigInteger ans, val(digits.back()); ans.isPositive = !(isPositive ^ num.isPositive); int ptr = digits.size(); ptr -= 2; val.isPositive = num.isPositive; while (ptr >= 0 && (num.isPositive ? val < num : num < val)) { val.addDigit(digits[ptr]); --ptr; } val.isPositive = true; for (; ptr >= -1; --ptr) { int number = 0; while (val >= 0) { num.isPositive ? val -= num : val += num; ++number; } num.isPositive ? val += num : val -= num; --number; ans.digits.push_back(number); if(ptr != -1) val.addDigit(digits[ptr]); } ans.reverseDigits(); ans.normilize(); return *this = ans; } BigInteger operator/(const BigInteger& num1, const BigInteger& num2) { BigInteger copy = num1; return copy /= num2; } BigInteger& BigInteger::operator%=(const BigInteger& num) { if(num == 0) return *this; BigInteger copy = (*this) / num; return *this -= (copy *= num); } BigInteger operator%(const BigInteger& num1, const BigInteger& num2) { BigInteger copy = num1; return copy %= num2; } bool BigInteger::operator<(const BigInteger& num) const { if (isPositive != num.isPositive) return num.isPositive; for (int j = std::max(static_cast(digits.size()), static_cast(num.digits.size())) - 1; j >= 0; --j) { unsigned int i = static_cast(j); if ((i < digits.size() ? digits[i] : 0) < (i < num.digits.size() ? num.digits[i] : 0)) return isPositive; if ((i < digits.size() ? digits[i] : 0) > (i < num.digits.size() ? num.digits[i] : 0)) return !isPositive; } return false; } bool BigInteger::operator>(const BigInteger& num) const { return num < *this; } bool BigInteger::operator==(const BigInteger& num) const { return !(num < *this || *this < num); } bool BigInteger::operator!=(const BigInteger& num) const { return num < *this || *this < num; } bool BigInteger::operator<=(const BigInteger& num) const { return !(num < *this); } bool BigInteger::operator>=(const BigInteger& num) const { return !(*this < num); } std::string BigInteger::toString() const { std::string num = ""; if (!isPositive) num += '-'; for (int i = digits.size() - 1; i >= 0; --i) { num += ('0' + digits[i]); } return num; } BigInteger::operator int() const { int value = 0; for (int i = digits.size() - 1; i >= 0; --i) value = value * 10 + digits[i]; if(!isPositive) value = -value; return value; } BigInteger::operator bool() const { return int(*this); } class Rational{ private: BigInteger numerator, denominator; void normilize(); static BigInteger gcd(const BigInteger&, const BigInteger&); static void reverse(std::string&); public: Rational(); Rational(const BigInteger&); Rational(const BigInteger& numerator, const BigInteger& denominator): numerator(numerator), denominator(denominator) {} Rational(int); Rational& operator+=(const Rational&); Rational operator+() const; Rational& operator-=(const Rational&); Rational operator-() const; Rational& operator*=(const Rational&); Rational& operator/=(const Rational&); bool operator<(const Rational&) const; bool operator>(const Rational&) const; bool operator==(const Rational&) const; bool operator!=(const Rational&) const; bool operator<=(const Rational&) const; bool operator>=(const Rational&) const; explicit operator double() const; std::string asDecimal(size_t) const; std::string toString() const; }; BigInteger Rational::gcd(const BigInteger& a, const BigInteger& b) { if (b == 0) return a; return gcd(b, a % b); } void Rational::normilize() { BigInteger _gcd = gcd(numerator, denominator); numerator /= _gcd; denominator /= _gcd; if (denominator < 0) { numerator *= -1; denominator *= -1; } } void Rational::reverse(std::string& s) { for(size_t i = 0; i < s.size()/2; ++i) { std::swap(s[i], s[s.size() - 1 - i]); } } Rational::Rational() : Rational(0) { } Rational::Rational(const BigInteger& val) { numerator = val; denominator = 1; } Rational::Rational(int val) { numerator = val; denominator = 1; } Rational& Rational::operator+=(const Rational& frac) { if (this == &frac) return *this += Rational(frac); numerator *= frac.denominator; numerator += denominator * frac.numerator; denominator *= frac.denominator; normilize(); return *this; } Rational operator+(const Rational& frac1, const Rational& frac2) { Rational copy = frac1; return copy += frac2; } Rational Rational::operator+() const { return *this; } Rational& Rational::operator-=(const Rational& frac) { if (this == &frac) return *this -= Rational(frac); numerator *= frac.denominator; numerator -= denominator * frac.numerator; denominator *= frac.denominator; normilize(); return *this; } Rational operator-(const Rational& frac1, const Rational& frac2) { Rational copy = frac1; return copy -= frac2; } Rational Rational::operator-() const { return Rational(0) -= *this; } Rational& Rational::operator*=(const Rational& frac) { if (this == &frac) return *this *= Rational(frac); numerator *= frac.numerator; denominator *= frac.denominator; normilize(); return *this; } Rational operator*(const Rational& frac1, const Rational& frac2) { Rational copy = frac1; return copy *= frac2; } Rational& Rational::operator/=(const Rational& frac) { if (frac.numerator == 0) return *this; if (this == &frac) return *this /= Rational(frac); numerator *= frac.denominator; denominator *= frac.numerator; normilize(); return *this; } Rational operator/(const Rational& frac1, const Rational& frac2) { Rational copy = frac1; return copy /= frac2; } bool Rational::operator<(const Rational& frac) const { return numerator * frac.denominator < frac.numerator * denominator; } bool Rational::operator>(const Rational& frac) const { return frac < *this; } bool Rational::operator==(const Rational& frac) const { return !(frac < *this || *this < frac); } bool Rational::operator!=(const Rational& frac) const { return frac < *this || *this < frac; } bool Rational::operator<=(const Rational& frac) const { return !(frac < *this); } bool Rational::operator>=(const Rational& frac) const { return !(*this < frac); } Rational::operator double() const { return std::stod(asDecimal(200)); } std::string Rational::asDecimal(size_t precision = 0u) const { BigInteger ten = 1; for (size_t i = 0; i < precision; ++i) { ten *= 10; } BigInteger val = (numerator < 0 ? -1 : 1) * numerator * ten / denominator; std::string integer = (val / ten).toString(); std::string frac = (val % ten).toString(); reverse(frac); while(frac.size() < precision) frac += '0'; frac += '.'; reverse(frac); if(precision == 0u) frac = ""; integer = (numerator < 0 ? "-" : "") + integer; return integer + frac; } std::string Rational::toString() const { std::string num = numerator.toString(); if (denominator != 1) { num += "/" + denominator.toString(); } return num; } std::ostream& operator<<(std::ostream& out, const Rational& value) { out << value.asDecimal(5); return out; } std::istream& operator>>(std::istream& in, Rational& value) { BigInteger numerator(0), denominator(0); bool was = false; char c; while (in.get(c)) { if (c == ' ' || c == '\n') break; if (c == '/') { was = true; } else { if (!was) { numerator *= 10; numerator += (c - '0'); } else { denominator *= 10; denominator += (c - '0'); } } } if (!was) { denominator = BigInteger(1); } value = Rational(numerator, denominator); return in; } bool isPrime(int N) { for (long long i = 2; i * i <= N; ++i) { if (N % i == 0) return false; } return true; } int fastPow(int a, int b, int module) { if (b == 0) return 1; if (b % 2 == 0) { long long val = fastPow(a, b / 2, module); return (val * val) % module; } else { return (1ll * fastPow(a, b - 1, module) * a) % module; } } int inverseValue(int value, int module) { return fastPow(value, module - 2, module); } template class Finite { public: Finite(int value = 0): value((value % N + N) % N), isPrimeN(isPrime(N)) {} Finite& operator+=(const Finite& number) { value = (value + number.value) % N; return *this; } Finite operator+(const Finite& number) const { Finite copy = *this; return copy += number; } Finite& operator-=(const Finite& number) { value = (value - number.value + N) % N; return *this; } Finite operator-(const Finite& number) const { Finite copy = *this; return copy -= number; } Finite operator-() const { return Finite(0 - value); } Finite& operator*=(const Finite& number) { value = (1ll * value * number.value) % N; return *this; } Finite operator*(const Finite& number) const { Finite copy = *this; return copy *= number; } Finite& operator/=(const Finite& number) { assert(isPrimeN); value = (1ll * value * inverseValue(number.value, N)) % N; return *this; } Finite operator/(const Finite& number) const { Finite copy = *this; return copy /= number; } bool operator==(const Finite& number) const { return value == number.value; } bool operator!=(const Finite& number) const { return value != number.value; } Finite& operator++() { return (*this += 1); } Finite operator++(int) { Finite copy; ++(*this); return copy; } template friend std::ostream& operator<<(std::ostream&, const Finite&); private: int value; bool isPrimeN; }; template std::ostream& operator<<(std::ostream& out, const Finite& value){ out << value.value; return out; } template class Matrix { public: Matrix(); template Matrix(std::initializer_list> a) { for (auto i: a) { table.push_back({}); for (auto j: i) { table.back().push_back(Field(j)); } } } Matrix(std::vector>&); Matrix(std::vector>&); template bool operator==(const Matrix&) const; template bool operator!=(const Matrix&) const; Matrix& operator+=(const Matrix&); Matrix operator+(const Matrix&) const; Matrix& operator-=(const Matrix&); Matrix operator-(const Matrix&) const; Matrix operator*(const Field&) const; Matrix& operator*=(const Matrix&); Field det() const; Matrix transposed() const; unsigned rank() const; Field trace() const; void invert(); Matrix inverted() const; std::vector getRow(unsigned) const; std::vector getColumn(unsigned) const; std::vector& operator[](size_t index) { return table[index]; } const std::vector& operator[](size_t index) const { return table[index]; } template friend class Matrix; private: std::vector> table; void swapStrings(unsigned, unsigned); void divideString(unsigned, const Field); void subtractStrings(unsigned, unsigned, const Field); Field makeSimple(); }; template Matrix::Matrix() { if (M != N) assert(0); table.resize(M, std::vector(N)); for (unsigned i = 0; i < N; ++i) { table[i][i] = Field(1); } } template Matrix::Matrix(std::vector>& matrix): table(matrix) {} template Matrix::Matrix(std::vector>& matrix) { table.resize(M, std::vector(N)); for (unsigned i = 0; i < M; ++i) { for (unsigned j = 0; j < N; ++j){ table[i][j] = Field(matrix[i][j]); } } } template template bool Matrix::operator==(const Matrix& matrix) const { if (!std::is_same, Matrix>::value) return false; for (unsigned i = 0; i < M; ++i) { for (unsigned j = 0; j < N; ++j) { if (table[i][j] != matrix[i][j]) return false; } } return true; } template template bool Matrix::operator!=(const Matrix& matrix) const { return !(*this == matrix); } template Matrix& Matrix::operator+=(const Matrix& matrix) { for (unsigned i = 0; i < M; ++i) { for (unsigned j = 0; j < N; ++j) { table[i][j] += matrix[i][j]; } } return *this; } template Matrix Matrix::operator+(const Matrix& matrix) const { Matrix copy = *this; return copy += matrix; } template Matrix& Matrix::operator-=(const Matrix& matrix) { for (unsigned i = 0; i < M; ++i) { for (unsigned j = 0; j < N; ++j) { table[i][j] -= matrix[i][j]; } } return *this; } template Matrix Matrix::operator-(const Matrix& matrix) const { Matrix copy = *this; return copy -= matrix; } template Matrix Matrix::operator*(const Field& multiplier) const { Matrix copy = *this; for (unsigned i = 0; i < M; ++i) { for (unsigned j = 0; j < N; ++j) { copy[i][j] *= multiplier; } } return copy; } template Matrix operator*(const Field& multiplier, const Matrix matrix) { return matrix * multiplier; } template Matrix operator*(const Matrix& matrix1, const Matrix& matrix2) { std::vector> resultTable(M, std::vector(K)); for (unsigned i = 0; i < M; ++i) { for (unsigned j = 0; j < K; ++j) { for (unsigned k = 0; k < N; ++k) { resultTable[i][j] += matrix1[i][k] * matrix2[k][j]; } } } return Matrix(resultTable); } template Matrix& Matrix::operator*=(const Matrix& matrix) { if (M != N) assert(0); return (*this = (*this) * matrix); } template Field Matrix::det() const { if (N != M) assert(0); Matrix copy = *this; return copy.makeSimple(); } template Matrix Matrix::transposed() const { std::vector> result(N, std::vector(M)); for (unsigned i = 0; i < N; ++i) { for (unsigned j = 0; j < M; ++j) { result[i][j] = table[j][i]; } } return Matrix(result); } template unsigned Matrix::rank() const { Matrix copy = *this; copy.makeSimple(); unsigned rank = 0; for (unsigned i = 0; i < M; ++i) { bool empty = true; for (unsigned j = 0; j < N; ++j) { if (copy[i][j] != 0) empty = false; } rank += !empty; } return rank; } template Field Matrix::trace() const { if (N != M) assert(0); Field result(0); for (unsigned i = 0; i < N; ++i) { result += table[i][i]; } return result; } template void Matrix::invert() { if (M != N) assert(0); if (N > 5){ std::cerr << "was:\n"; for(unsigned i = 0; i < 10; ++i) { for(unsigned j = 0; j < 20; ++j){ std::cerr << table[i][j] << " "; } std::cerr << std::endl; } } std::vector> complexTable(N, std::vector(2 * N)); for (unsigned i = 0; i < N; ++i) { for (unsigned j = 0; j < N; ++j) { complexTable[i][j] = table[i][j]; } } for (unsigned i = 0; i < N; ++i) complexTable[i][i + N] = Field(1); Matrix complexMatrix(complexTable); complexMatrix.makeSimple(); std::vector> result(N, std::vector(N)); for (unsigned i = 0; i < M; ++i) { for (unsigned j = 0; j < N; ++j) { result[i][j] = complexMatrix[i][j + N]; } } if (N > 100){ std::cerr << "now:\n"; for(unsigned i = 0; i < M; ++i) { for(unsigned j = 0; j < N; ++j){ std::cerr << result[i][j] << " "; } std::cerr << std::endl; } } *this = Matrix(result); } template Matrix Matrix::inverted() const { Matrix matrix = *this; matrix.invert(); return matrix; } template std::vector Matrix::getRow(unsigned int index) const { return table[index]; } template std::vector Matrix::getColumn(unsigned int index) const { std::vector result(M); for (unsigned i = 0; i < M; ++i) { result[i] = table[i][index]; } return result; } template void Matrix::swapStrings(unsigned index1, unsigned index2) { std::swap(table[index1], table[index2]); } template void Matrix::divideString(unsigned index, const Field divisor) { for (unsigned i = 0; i < N; ++i) { table[index][i] /= divisor; } } template void Matrix::subtractStrings(unsigned indexMinuend, unsigned indexSubtrahend, const Field multiplier) { for (unsigned i = 0; i < N; ++i) { table[indexMinuend][i] -= table[indexSubtrahend][i] * multiplier; } } template Field Matrix::makeSimple() { Field determinant(1); unsigned string = 0; for (unsigned i = 0; i < N; ++i) { unsigned found = M + 1; for (unsigned j = string; j < M; ++j) { if (table[j][i] != Field(0)) { found = j; break; } } if (found == M + 1){ determinant = 0; continue; } swapStrings(string, found); determinant *= table[string][i]; divideString(string, table[string][i]); for (unsigned j = 0; j < M; ++j) { if (j != string) subtractStrings(j, string, table[j][i]); } ++string; } return determinant; } template using SquareMatrix = Matrix;