#include #include #include #include using namespace std; template struct is_prime_ { static const bool value = !(N % i == 0) && is_prime_::value; }; template struct is_prime_ { static const bool value = false; }; template struct is_prime_ { static const bool value = true; }; template struct is_prime { static const bool value = (is_prime_::value && (N != 1)) || (N == 2); }; template static const bool is_prime_v = is_prime::value; template struct is_power_of_prime_ { static const bool value = is_power_of_prime_= N ? 1 : N)), N % i == 0 ? i : i + 2, N % i == 0>::value; }; template struct is_power_of_prime_<1, i, find_divider> { static const bool value = true; }; template struct is_power_of_prime_<0, i, find_divider> { static const bool value = false; }; template struct is_power_of_prime { static const bool value = is_power_of_prime_::value; }; template 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 static const bool has_primitive_root_v = has_primitive_root::value; template 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 class Residue { public: Residue() = default; Residue(const Residue& another) = default; explicit Residue(long long x) : x(x) { Normilize(); } explicit operator int() const { return x; } bool operator==(const Residue& another) { return x == another.x; } bool operator!=(const Residue& another) { return !(*this == another); } Residue& operator+=(const Residue& another); Residue& operator-=(const Residue& another); Residue& operator*=(const Residue& another); Residue& operator/=(const Residue& another); Residue getInverse() const { cerr << "getInverse " << x << " " << Modulus << endl; my_static_assert>(); return Residue(pow(x, Modulus - 2)); } unsigned order() const { cerr << "order " << x << " " << Modulus << endl; unsigned phi = ::phi(Modulus); unsigned copy_phi = phi; std::vector 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() { cerr << "getPrimitiveRoot " << Modulus << endl; my_static_assert>(); if (Modulus == 2) { return Residue(1); } else if (Modulus == 4) { return Residue(3); } unsigned phi = ::phi(Modulus); unsigned copy_phi = phi; std::vector 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 pow(unsigned degree) const; private: static int pow(int x, unsigned degree); void Normilize() { x %= static_cast(Modulus); if (x < 0) x += Modulus; } long long x; }; template Residue& Residue::operator+=(const Residue& another) { x += another.x; Normilize(); return *this; } template Residue& Residue::operator-=(const Residue& another) { x -= another.x; Normilize(); return *this; } template Residue& Residue::operator*=(const Residue& another) { x *= another.x; Normilize(); return *this; } template Residue& Residue::operator/=(const Residue& another) { *this *= another.getInverse(); return *this; } template Residue operator+(const Residue& a, const Residue& b) { Residue tmp(a); tmp += b; return tmp; } template Residue operator-(const Residue& a, const Residue& b) { Residue tmp(a); tmp -= b; return tmp; } template Residue operator*(const Residue& a, const Residue& b) { Residue tmp(a); tmp *= b; return tmp; } template Residue operator/(const Residue& a, const Residue& b) { Residue tmp(a); tmp /= b; return tmp; } template Residue Residue::pow(unsigned degree) const { return Residue(pow(x, degree)); } template int Residue::pow(int x, unsigned degree) { if (degree == 0) { return 1; } else { long long t = pow(x, degree / 2); return (((t * t) % static_cast(Modulus)) * (degree % 2 == 0 ? 1 : x)) % static_cast(Modulus); } }