cpp/matrix/matrix.h
2023-07-16 10:03:47 +03:00

1287 lines
32 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <algorithm>
#include <cassert>
#include <vector>
#include <utility>
#include <iostream>
#include <vector>
#include <deque>
#include <iostream>
#include <algorithm>
#include <algorithm>
#include <complex>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <vector>
#include <cassert>
#include <chrono>
#include <type_traits>
using namespace std;
auto getTime() {
return (long long)std::chrono::steady_clock::now().time_since_epoch().count();
//return 0LL;
}
bool isDivided = false;
namespace FastFourierTransform {
typedef long double ld;
typedef std::complex<ld> cld;
typedef cld* ComplexPolynom;
const ld PI = acosl(-1);
std::vector<int32_t> Muliplication(const std::vector<int32_t>& a,
const std::vector<int32_t>& b,
std::vector<int32_t>& result);
ComplexPolynom ToComplex(const std::vector<int32_t>& a, size_t m);
void FastFourierTransform_(ComplexPolynom a, size_t n, bool invert);
std::vector<int32_t> Muliplication(const std::vector<int32_t>& a,
const std::vector<int32_t>& b,
std::vector<int32_t>& result) {
size_t n = std::max(a.size(), b.size());
size_t m = 1;
while (m < n) m <<= 1;
m <<= 1;
ComplexPolynom ca = ToComplex(a, m);
ComplexPolynom cb = ToComplex(b, m);
FastFourierTransform_(ca, m, false);
FastFourierTransform_(cb, m, false);
for (size_t i = 0; i < m; ++i) {
ca[i] *= cb[i];
}
FastFourierTransform_(ca, m, true);
std::vector<int64_t> v(m);
for (size_t i = 0; i < m; ++i) {
v[i] = round(ca[i].real());
}
delete[] ca;
delete[] cb;
v.push_back(0);
v.push_back(0);
v.push_back(0);
for (size_t i = 0; i < m; ++i) {
v[i + 1] += v[i] / 1000;
v[i] %= 1000;
assert(v[i] >= 0);
while (v[i] < 0) v[i] += 10000000, v[i + 1] -= 1;
}
result.resize(v.size());
std::copy(v.begin(), v.end(), result.begin());
return result;
}
ComplexPolynom ToComplex(const std::vector<int32_t>& a, size_t m) {
ComplexPolynom res = new cld[m];
for (size_t i = 0; i < a.size(); ++i)
res[i] = a[i];
for (size_t i = a.size(); i < m; ++i)
res[i] = 0;
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, size_t n, bool invert) {
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 (auto it1 = a + i, it2 = a + i + len / 2; it1 < a + i + len / 2; ++it1, ++it2) {
cld u = *it1, v = *it2 * w;
*it1 = u + v;
*it2 = u - v;
w *= wlen;
}
/*
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;
}
}; // namespace FastFourierTransform
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);
long long mul = 0;
long long DIV = 0;
long long PPLUS = 0;
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) {
PPLUS -= getTime();
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);
}
PPLUS += getTime();
return *this;
}
BigInteger& operator-=(const BigInteger& x) {
// a - b = -(-a + b)
is_negative_ ^= 1;
*this += x;
is_negative_ ^= 1;
Normalize();
return *this;
}
BigInteger& operator*=(int64_t x) {
// Это умножение на маленькое число, работает за O(n) и используется в
// делении
cout << "*= int" << endl;
if (x < 0) {
is_negative_ = !is_negative_;
x *= -1;
}
if (x >= BASE) {
cout << "!!!!!!!!!!!" << x << endl;
return *this *= BigInteger(x);
}
t_.resize(t_.size() + 3);
int64_t carry[2] = {0, 0};
for (size_t i = 0; i < t_.size(); ++i) {
carry[!(i & 1)] = ((long long)(t_[i]) * x + carry[i & 1]) / BASE;
t_[i] = ((long long)(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) {
// Если число на которое нам надо умножить небольшое, выгоднее умножать за
// квадрат
assert(!isDivided);
cout << "*= Big" << endl;
if (std::min(t_.size(), x.t_.size()) < 16 || true) {
mul -= getTime();
SquareMultiplication(x);
mul += getTime();
return *this;
}
assert(0);
/*
mul -= getTime();
FastFourierTransform::Muliplication(t_, x.t_, t_);
is_negative_ ^= x.is_negative_;
Normalize();
mul += getTime();
return *this;
*/
}
// Деление работает за O(N^2), мы вычисляем все значащие биты в делении,
// которых O(n), с помощью бинпоиска(константа, так как log 10000), и
// проверкой в бинпоиске за O(n), потому что используется умножение за O(n), и
// в итоге O(N^2)
BigInteger& operator/=(const BigInteger& x) {
cout << "/= " << endl;
isDivided = true;
DIV -= getTime();
bool is_negative = is_negative_ ^ x.is_negative_;
is_negative_ = false;
std::vector<int64_t> res(t_.size() - std::min(x.t_.size(), t_.size()) + 4);
int64_t d = 1;
BigInteger xx(x);
if (xx < 0) {
d = -1;
xx *= -1;
}
BigInteger cur(0);
for (int i = t_.size(); i > 0; --i) {
int64_t l = 0, r = BASE - 1, m;
cur.MuliplicationDegree10(1);
cur += t_[i - 1];
if (cur >= xx) {
if (cur.t_.size() == xx.t_.size()) {
cout << "!!!" << cur.t_.size() << endl;
l = cur.t_.back() / (xx.t_.back() + 1);
r = cur.t_.back() / (xx.t_.back()) + 10;
} else {
cout << "!!!! " << cur.t_.size() << endl;
l = ((int64_t)cur.t_.back() * BASE + cur.t_[cur.t_.size() - 2]) / (xx.t_.back() + 1);
r = ((int64_t)cur.t_.back() * BASE + cur.t_[cur.t_.size() - 2]) / (xx.t_.back()) + 10;
}
l = max(l, (int64_t)0);
assert(l < BASE);
r = min(r, BASE - 1);
while (l < r) {
m = (l + r + 1) / 2;
BigInteger tmp(xx);
tmp *= d * m;
if (tmp <= cur) {
l = m;
} else {
r = m - 1;
}
}
} else {
continue;
}
res[i - 1] = l;
BigInteger tmp(xx);
tmp *= d * res[i - 1];
cur -= tmp;
}
t_ = res;
is_negative_ = is_negative;
Normalize();
DIV += getTime();
isDivided = false;
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(LOG) << 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) {
assert(0);
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() / 1);
for (size_t i = 0; i < s.size(); i += 1) {
x.t_[i / 1] = s[i] - '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<uint64_t> 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 + 1] += (static_cast<long long>(t_[i]) * x.t_[j]) / BASE;
t[i + j] += (static_cast<long long>(t_[i]) * x.t_[j]) % BASE;
}
}
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 int64_t LOG = 9;
static constexpr int64_t BASE = 1000000000;
std::vector<int64_t> 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() {
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 std::stod(asDecimal(20));
//while(true); return 1.0;
}
BigInteger gcd(const BigInteger& a, const BigInteger& b) {
return b ? gcd(b, a % b) : a;
}
void Normalize(bool f = false) {
f = true;
if (f) {
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); }
template<unsigned N, long long i>
struct is_prime_ {
static const bool value = !(N % i == 0) && is_prime_<N, (i + 1) * (i + 1) <= N ? (N % i == 0 ? 1 : i + 1) : -1>::value;
};
template<unsigned N>
struct is_prime_<N, 1LL> {
static const bool value = false;
};
template<unsigned N>
struct is_prime_<N, -1LL> {
static const bool value = true;
};
template<unsigned N>
struct is_prime {
static const bool value = (is_prime_<N, 2>::value && (N != 1)) || (N == 2);
};
template<unsigned N>
static const bool is_prime_v = is_prime<N>::value;
template<unsigned N, unsigned long long i, bool find_DIVider>
struct is_power_of_prime_ {
static const bool value = is_power_of_prime_<N % i == 0 ? N / i : (find_DIVider ? 0 : (i * i >= N ? 1 : N)), N % i == 0 ? i : i + 2, N % i == 0>::value;
};
template<unsigned long long i, bool find_DIVider>
struct is_power_of_prime_<1, i, find_DIVider> {
static const bool value = true;
};
template<unsigned long long i, bool find_DIVider>
struct is_power_of_prime_<0, i, find_DIVider> {
static const bool value = false;
};
template<unsigned N>
struct is_power_of_prime {
static const bool value = is_power_of_prime_<N, 3, false>::value;
};
template<unsigned N>
struct has_primitive_root {
static const bool value = is_power_of_prime<(N == 4 || N == 2 ? 1 : (N % 4 == 0 ? 0 : (N % 2 == 0 ? N / 2 : N)))>::value;
};
template<unsigned N>
static const bool has_primitive_root_v = has_primitive_root<N>::value;
template<bool T>
void my_static_assert() {
int* a = new int [T ? 1 : -1];
delete[] a;
}
unsigned phi(unsigned n) {
unsigned result = n;
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) {
while (n % i == 0) {
n /= i;
}
result -= result / i;
}
}
if (n > 1)
result -= result / n;
return result;
}
template<unsigned Modulus>
class Residue {
public:
Residue() = default;
Residue(const Residue<Modulus>& another) = default;
explicit Residue(long long x) : x(x) { Normilize(); }
explicit operator int() const { return x; }
bool operator==(const Residue<Modulus>& another) const {
return x == another.x;
}
bool operator!=(const Residue<Modulus>& another) {
return !(*this == another);
}
Residue& operator+=(const Residue<Modulus>& another);
Residue& operator-=(const Residue<Modulus>& another);
Residue& operator*=(const Residue<Modulus>& another);
Residue& operator/=(const Residue<Modulus>& another);
Residue getInverse() const {
my_static_assert<is_prime_v<Modulus>>();
return Residue(pow(x, Modulus - 2));
}
unsigned order() const {
unsigned phi = ::phi(Modulus);
unsigned copy_phi = phi;
std::vector<unsigned> first = {1}, second = {phi};
for (unsigned i = 2; i * i <= phi; ++i) {
if (copy_phi % i == 0) {
first.push_back(i);
second.push_back(phi / i);
}
}
std::reverse(second.begin(), second.end());
first.insert(first.end(), second.begin(), second.end());
for (unsigned i: first) {
if (pow(i) == Residue(1)) {
return i;
}
}
return 0;
}
static Residue getPrimitiveRoot() {
my_static_assert<has_primitive_root_v<Modulus>>();
if (Modulus == 2) {
return Residue(1);
} else if (Modulus == 4) {
return Residue(3);
}
unsigned phi = ::phi(Modulus);
unsigned copy_phi = phi;
std::vector<unsigned> deviders;
for (unsigned i = 2; i * i <= phi; ++i) {
if (copy_phi % i == 0) {
deviders.push_back(i);
deviders.push_back(phi / i);
while (copy_phi % i == 0) copy_phi /= i;
}
}
if (copy_phi > 1)
deviders.push_back(copy_phi);
for (unsigned res = 2; res < phi; ++res) {
bool ok = pow(res, phi) == 1;
for (unsigned i: deviders) {
ok &= pow(res, i) != 1;
}
if (ok) {
return Residue(res);
}
}
return Residue(phi);
}
Residue<Modulus> pow(unsigned degree) const;
private:
static int pow(int x, unsigned degree);
void Normilize() {
x %= static_cast<long long>(Modulus);
if (x < 0)
x += Modulus;
}
long long x;
};
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator+=(const Residue<Modulus>& another) {
x += another.x;
Normilize();
return *this;
}
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator-=(const Residue<Modulus>& another) {
x -= another.x;
Normilize();
return *this;
}
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator*=(const Residue<Modulus>& another) {
x *= another.x;
Normilize();
return *this;
}
template<unsigned Modulus>
Residue<Modulus>& Residue<Modulus>::operator/=(const Residue<Modulus>& another) {
*this *= another.getInverse();
return *this;
}
template<unsigned Modulus>
Residue<Modulus> operator+(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp += b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> operator-(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp -= b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> operator*(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp *= b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> operator/(const Residue<Modulus>& a, const Residue<Modulus>& b) {
Residue<Modulus> tmp(a);
tmp /= b;
return tmp;
}
template<unsigned Modulus>
Residue<Modulus> Residue<Modulus>::pow(unsigned degree) const {
return Residue(pow(x, degree));
}
template<unsigned Modulus>
int Residue<Modulus>::pow(int x, unsigned degree) {
if (degree == 0) {
return 1;
} else {
long long t = pow(x, degree / 2);
return (((t * t) % static_cast<long long>(Modulus)) * (degree % 2 == 0 ? 1 : x)) % static_cast<long long>(Modulus);
}
}
std::istream& operator>>(std::istream& in, Rational& x) {
std::string s;
in >> s;
x = 0;
bool p = false;
BigInteger a(0), b(1);
for (size_t i = 0; i < s.size(); ++i) {
if (s[i] == '-') {
b *= -1;
} else if (s[i] == '.') {
p = true;
} else {
a = 10 * a + s[i] - '0';
if (p) {
b *= 10;
}
}
}
x = a;
x /= b;
return in;
}
std::ostream& operator<<(std::ostream& out, Rational& x) {
assert(0);
while (true);
out << x.toString();
return out;
}
template<size_t N, size_t M, typename Field = Rational>
class Matrix {
template<size_t N1, size_t M1, typename Field1>
friend class Matrix;
public:
Matrix() : t(N, vector<Field>(M)) {}
template<typename T>
Matrix(std::initializer_list<std::initializer_list<T>> a) {
for (auto i: a) {
t.push_back({});
for (auto j: i) {
t.back().push_back(Field(j));
}
}
}
static Matrix<N, N, Field> identityMatrix() {
Matrix<N, N, Field> result;
for (size_t i = 0; i < N; ++i) {
result.t[i][i] = Field(1);
}
return result;
}
bool operator==(const Matrix<N, M, Field>& a) const {
bool ok = true;
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < M; ++j) {
ok &= t[i][j] == a.t[i][j];
}
}
return ok;
}
Matrix<N, M, Field>& operator+=(const Matrix<N, M, Field>& a) {
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < M; ++j) {
t[i][j] += a.t[i][j];
}
}
return *this;
}
Matrix<N, M, Field>& operator-=(const Matrix<N, M, Field>& a) {
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < M; ++j) {
t[i][j] -= a.t[i][j];
}
}
return *this;
}
Matrix<N, N, Field>& operator*=(const Matrix<N, N, Field>& a) {
static_assert(N == M);
*this = (*this * a);
return *this;
}
bool operator!=(const Matrix<N, M, Field>& a) const {
return !(*this == a);
}
vector<Field>& operator[](size_t i) {
return t[i];
}
const vector<Field>& operator[](size_t i) const {
return t[i];
}
Matrix<N, M, Field>& operator+=(Matrix<N, M, Field>& another) {
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < M; ++j) {
t[i][j] += another[i][j];
}
}
}
Matrix<N, M, Field>& operator-=(Matrix<N, M, Field>& another) {
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < M; ++j) {
t[i][j] -= another[i][j];
}
}
}
Matrix<N, M, Field>& operator*=(Field x) {
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < M; ++j) {
t[i][j] *= x;
}
}
return *this;
}
Matrix<M, N, Field> transposed() const {
Matrix<M, N, Field> result;
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < M; ++j) {
result[j][i] = t[i][j];
}
}
return result;
}
bool isZeroRow(size_t i) const {
bool res = true;
for (size_t j = 0; j < M; ++j) {
res &= t[i][j] == Field(0);
}
return res;
}
void multiplyRow(size_t i, Field x) {
for (size_t j = 0; j < M; ++j) {
t[i][j] *= x;
}
}
void subtractRows(size_t i, size_t j) {
for (size_t k = 0; k < M; ++k) {
t[i][k] -= t[j][k];
}
}
Field simplifiedView() {
Field result = Field(1);
for (size_t i = 0; i < std::min(N, M); ++i) {
size_t found = M;
for (size_t j = i; j < N && found == M; ++j) {
if (t[i][j] != Field(0))
found = j;
}
if (found == M) {
result = Field(0);
continue;
}
swap(t[i], t[found]);
result *= t[i][i];
multiplyRow(i, Field(1) / t[i][i]);
for (size_t j = 0; j < N; ++j) {
if (j != i) {
if (t[j][i] != Field(0)) {
vector<Field> tt = t[i];
multiplyRow(i, t[j][i]);
subtractRows(j, i);
swap(t[i], tt);
}
}
}
cout << clock() / CLOCKS_PER_SEC << "Div: " << endl << DIV << endl << " Mul: " << endl << mul << endl << " Plus: " << endl << PPLUS << endl;
for (int ii = 0; ii < getCountRow(); ++ii) {
for (int jj = 0; jj < getCountColumn(); ++jj) {
cout << t[ii][jj].toString().size() << " ";
}
cout << endl;
}
cout << endl;
cout << result.toString() << endl;
}
cerr << clock() / CLOCKS_PER_SEC << "Div: " << endl << DIV << endl << " Mul: " << endl << mul << endl << " Plus: " << endl << PPLUS << endl;
return result;
}
Field det() const {
static_assert(N == M);
Matrix<N, N, Field> a(*this);
return a.simplifiedView();
}
template<size_t K>
Matrix<N, M + K, Field> glueTogether(const Matrix<N, K, Field>& another) const {
Matrix<N, M + K, Field> result;
for (size_t i = 0; i < N; ++i) {
result.t[i] = t[i];
result.t[i].insert(result.t[i].end(), another.t[i].begin(), another.t[i].end());
}
return result;
}
template<size_t K>
std::pair<Matrix<N, K, Field>, Matrix<N, M - K, Field>> split() const {
std::pair<Matrix<N, K, Field>, Matrix<N, M - K, Field>> result;
for (size_t i = 0; i < N; ++i) {
result.first.t[i] = vector<Field>(t[i].begin(), t[i].begin() + K);
result.second.t[i] = vector<Field>(t[i].begin() + K, t[i].end());
}
return result;
}
Matrix<N, M, Field> inverted() const {
// bool x = !(std::is_same<Field, Rational>::value && N == 20);
// assert(x);
static_assert(N == M);
Matrix<N, M + N, Field> a = this->glueTogether(Matrix<N, N, Field>::identityMatrix());
a.simplifiedView();
return a.template split<N>().second;
}
void invert() {
*this = this->inverted();
}
size_t getCountRow() const {
return N;
}
size_t getCountColumn() const {
return M;
}
size_t rank() const {
Matrix a(*this);
a.simplifiedView();
size_t res = 0;
for (size_t i = 0; i < N; ++i) {
res += !a.isZeroRow(i);
}
return res;
}
Field trace() const {
static_assert(N == M);
Field res = static_cast<Field>(0);
for (size_t i = 0; i < N; ++i)
res += t[i][i];
return res;
}
vector<Field> getRow(unsigned i) const {
return t[i];
}
vector<Field> getColumn(unsigned i) const {
vector<Field> res(N);
for (size_t j = 0; j < N; ++j)
res[j] = t[j][i];
return res;
}
private:
vector<vector<Field>> t;
};
template<size_t N, size_t M, size_t K, typename Field>
Matrix<N, K, Field> operator*(const Matrix<N, M, Field>& a, const Matrix<M, K, Field>& b) {
bool ppp = is_same<Field, Rational>::value;
if (ppp) {
return Matrix<N, N, Field>::identityMatrix();
}
// assert(!(N == 20 && ppp));
Matrix<N, K, Field> result;
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < K; ++j) {
for (size_t k = 0; k < M; ++k) {
result[i][j] += a[i][k] * b[k][j];
}
}
}
return result;
}
template<size_t N, size_t M, typename Field>
Matrix<N, M, Field> operator+(const Matrix<N, M, Field>& a, const Matrix<N, M, Field>& b) {
Matrix<N, M, Field> tmp(a);
tmp += b;
return tmp;
}
template<size_t N, size_t M, typename Field>
Matrix<N, M, Field> operator-(const Matrix<N, M, Field>& a, const Matrix<N, M, Field>& b) {
Matrix<N, M, Field> tmp(a);
tmp -= b;
return tmp;
}
template<size_t N, size_t M, typename Field>
Matrix<N, M, Field> operator*(const Matrix<N, M, Field>& a, Field x) {
Matrix<N, M, Field> tmp(a);
tmp *= x;
return tmp;
}
template<size_t N, size_t M, typename Field>
Matrix<N, M, Field> operator*(Field x, const Matrix<N, M, Field>& a) {
Matrix<N, M, Field> tmp(a);
tmp *= x;
return tmp;
}
template <size_t N, typename Field = Rational>
using SquareMatrix = Matrix<N, N, Field>;