This documentation is automatically generated by competitive-verifier/competitive-verifier
// @brief Primitive Root
#define PROBLEM "https://judge.yosupo.jp/problem/primitive_root"
#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("tune=native")
#include "cp-algo/math/number_theory.hpp"
#include <bits/stdc++.h>
using namespace std;
using namespace cp_algo;
using namespace math;
using base = dynamic_modint;
void solve() {
int64_t p;
cin >> p;
cout << primitive_root(p) << "\n";
}
signed main() {
//freopen("input.txt", "r", stdin);
ios::sync_with_stdio(0);
cin.tie(0);
int t = 1;
cin >> t;
while(t--) {
solve();
}
}
#line 1 "verify/number_theory/primitive_root.test.cpp"
// @brief Primitive Root
#define PROBLEM "https://judge.yosupo.jp/problem/primitive_root"
#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("tune=native")
#line 1 "cp-algo/math/number_theory.hpp"
#line 1 "cp-algo/random/rng.hpp"
#include <chrono>
#include <random>
namespace cp_algo::random {
uint64_t rng() {
static std::mt19937_64 rng(
std::chrono::steady_clock::now().time_since_epoch().count()
);
return rng();
}
}
#line 1 "cp-algo/math/affine.hpp"
#include <optional>
#include <utility>
#include <cassert>
#include <tuple>
namespace cp_algo::math {
// a * x + b
template<typename base>
struct lin {
base a = 1, b = 0;
std::optional<base> c;
lin() {}
lin(base b): a(0), b(b) {}
lin(base a, base b): a(a), b(b) {}
lin(base a, base b, base _c): a(a), b(b), c(_c) {}
// polynomial product modulo x^2 - c
lin operator * (const lin& t) {
assert(c && t.c && *c == *t.c);
return {a * t.b + b * t.a, b * t.b + a * t.a * (*c), *c};
}
// a * (t.a * x + t.b) + b
lin apply(lin const& t) const {
return {a * t.a, a * t.b + b};
}
void prepend(lin const& t) {
*this = t.apply(*this);
}
base eval(base x) const {
return a * x + b;
}
};
// (ax+b) / (cx+d)
template<typename base>
struct linfrac {
base a, b, c, d;
linfrac(): a(1), b(0), c(0), d(1) {} // x, identity for composition
linfrac(base a): a(a), b(1), c(1), d(0) {} // a + 1/x, for continued fractions
linfrac(base a, base b, base c, base d): a(a), b(b), c(c), d(d) {}
// composition of two linfracs
linfrac operator * (linfrac t) const {
return t.prepend(linfrac(*this));
}
linfrac operator-() const {
return {-a, -b, -c, -d};
}
linfrac adj() const {
return {d, -b, -c, a};
}
linfrac& prepend(linfrac const& t) {
t.apply(a, c);
t.apply(b, d);
return *this;
}
// apply linfrac to A/B
void apply(base &A, base &B) const {
std::tie(A, B) = std::pair{a * A + b * B, c * A + d * B};
}
};
}
#line 1 "cp-algo/math/modint.hpp"
#line 1 "cp-algo/math/common.hpp"
#include <functional>
#include <cstdint>
namespace cp_algo::math {
#ifdef CP_ALGO_MAXN
const int maxn = CP_ALGO_MAXN;
#else
const int maxn = 1 << 19;
#endif
const int magic = 64; // threshold for sizes to run the naive algo
auto bpow(auto const& x, int64_t n, auto const& one, auto op) {
if(n == 0) {
return one;
} else {
auto t = bpow(x, n / 2, one, op);
t = op(t, t);
if(n % 2) {
t = op(t, x);
}
return t;
}
}
auto bpow(auto x, int64_t n, auto ans) {
return bpow(x, n, ans, std::multiplies{});
}
template<typename T>
T bpow(T const& x, int64_t n) {
return bpow(x, n, T(1));
}
}
#line 4 "cp-algo/math/modint.hpp"
#include <iostream>
namespace cp_algo::math {
template<typename modint>
struct modint_base {
static int64_t mod() {
return modint::mod();
}
modint_base(): r(0) {}
modint_base(int64_t rr): r(rr % mod()) {
r = std::min(r, r + mod());
}
modint inv() const {
return bpow(to_modint(), mod() - 2);
}
modint operator - () const {return std::min(-r, mod() - r);}
modint& operator /= (const modint &t) {
return to_modint() *= t.inv();
}
modint& operator *= (const modint &t) {
if(mod() <= uint32_t(-1)) {
r = r * t.r % mod();
} else {
r = __int128(r) * t.r % mod();
}
return to_modint();
}
modint& operator += (const modint &t) {
r += t.r; r = std::min(r, r - mod());
return to_modint();
}
modint& operator -= (const modint &t) {
r -= t.r; r = std::min(r, r + mod());
return to_modint();
}
modint operator + (const modint &t) const {return modint(to_modint()) += t;}
modint operator - (const modint &t) const {return modint(to_modint()) -= t;}
modint operator * (const modint &t) const {return modint(to_modint()) *= t;}
modint operator / (const modint &t) const {return modint(to_modint()) /= t;}
auto operator <=> (const modint_base &t) const = default;
int64_t rem() const {return 2 * r > (uint64_t)mod() ? r - mod() : r;}
// Only use if you really know what you're doing!
uint64_t modmod() const {return 8ULL * mod() * mod();};
void add_unsafe(uint64_t t) {r += t;}
void pseudonormalize() {r = std::min(r, r - modmod());}
modint const& normalize() {
if(r >= (uint64_t)mod()) {
r %= mod();
}
return to_modint();
}
uint64_t& setr() {return r;}
uint64_t getr() const {return r;}
private:
uint64_t r;
modint& to_modint() {return static_cast<modint&>(*this);}
modint const& to_modint() const {return static_cast<modint const&>(*this);}
};
template<typename modint>
std::istream& operator >> (std::istream &in, modint_base<modint> &x) {
return in >> x.setr();
}
template<typename modint>
std::ostream& operator << (std::ostream &out, modint_base<modint> const& x) {
return out << x.getr();
}
template<typename modint>
concept modint_type = std::is_base_of_v<modint_base<modint>, modint>;
template<int64_t m>
struct modint: modint_base<modint<m>> {
static constexpr int64_t mod() {return m;}
using Base = modint_base<modint<m>>;
using Base::Base;
};
struct dynamic_modint: modint_base<dynamic_modint> {
static int64_t mod() {return m;}
static void switch_mod(int64_t nm) {m = nm;}
using Base = modint_base<dynamic_modint>;
using Base::Base;
// Wrapper for temp switching
auto static with_mod(int64_t tmp, auto callback) {
struct scoped {
int64_t prev = mod();
~scoped() {switch_mod(prev);}
} _;
switch_mod(tmp);
return callback();
}
private:
static int64_t m;
};
int64_t dynamic_modint::m = 0;
}
#line 6 "cp-algo/math/number_theory.hpp"
#include <algorithm>
#line 8 "cp-algo/math/number_theory.hpp"
#include <vector>
#include <bit>
namespace cp_algo::math {
std::vector<int64_t> factorize(int64_t m);
int64_t euler_phi(int64_t m) {
auto primes = factorize(m);
auto [from, to] = std::ranges::unique(primes);
primes.erase(from, to);
int64_t ans = m;
for(auto it: primes) {
ans -= ans / it;
}
return ans;
}
template<modint_type base>
int64_t period(base x) {
auto ans = euler_phi(base::mod());
base x0 = bpow(x, ans);
for(auto t: factorize(ans)) {
while(ans % t == 0 && x0 * bpow(x, ans / t) == x0) {
ans /= t;
}
}
return ans;
}
// Find min non-negative x s.t. a*b^x = c (mod m)
std::optional<uint64_t> discrete_log(int64_t b, int64_t c, uint64_t m, int64_t a = 1) {
if(std::abs(a - c) % m == 0) {
return 0;
}
if(std::gcd(a, m) != std::gcd(a * b, m)) {
auto res = discrete_log(b, c, m, a * b % m);
return res ? std::optional(*res + 1) : res;
}
// a * b^x is periodic here
using base = dynamic_modint;
return base::with_mod(m, [&]() -> std::optional<uint64_t> {
size_t sqrtmod = std::max<size_t>(1, std::sqrt(m) / 2);
std::unordered_map<int64_t, int> small;
base cur = a;
for(size_t i = 0; i < sqrtmod; i++) {
small[cur.getr()] = i;
cur *= b;
}
base step = bpow(base(b), sqrtmod);
cur = 1;
for(size_t k = 0; k < m; k += sqrtmod) {
auto it = small.find((base(c) * cur).getr());
if(it != end(small)) {
auto cand = base::with_mod(period(base(b)), [&](){
return base(it->second - k);
}).getr();
if(base(a) * bpow(base(b), cand) == base(c)) {
return cand;
} else {
return std::nullopt;
}
}
cur *= step;
}
return std::nullopt;
});
}
// https://en.wikipedia.org/wiki/Berlekamp-Rabin_algorithm
template<modint_type base>
std::optional<base> sqrt(base b) {
if(b == base(0)) {
return base(0);
} else if(bpow(b, (b.mod() - 1) / 2) != base(1)) {
return std::nullopt;
} else {
while(true) {
base z = random::rng();
if(z * z == b) {
return z;
}
lin<base> x(1, z, b); // x + z (mod x^2 - b)
x = bpow(x, (b.mod() - 1) / 2, lin<base>(0, 1, b));
if(x.a != base(0)) {
return x.a.inv();
}
}
}
}
// https://en.wikipedia.org/wiki/Miller–Rabin_primality_test
bool is_prime(uint64_t m) {
if(m == 1 || m % 2 == 0) {
return m == 2;
}
// m - 1 = 2^s * d
int s = std::countr_zero(m - 1);
auto d = (m - 1) >> s;
using base = dynamic_modint;
auto test = [&](base x) {
x = bpow(x, d);
if(std::abs(x.rem()) <= 1) {
return true;
}
for(int i = 1; i < s && x != -1; i++) {
x *= x;
}
return x == -1;
};
return base::with_mod(m, [&](){
// Works for all m < 2^64: https://miller-rabin.appspot.com
return std::ranges::all_of(std::array{
2, 325, 9375, 28178, 450775, 9780504, 1795265022
}, test);
});
}
// https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
void factorize(uint64_t m, std::vector<int64_t> &res) {
if(m % 2 == 0) {
factorize(m / 2, res);
res.push_back(2);
} else if(is_prime(m)) {
res.push_back(m);
} else if(m > 1) {
using base = dynamic_modint;
base::with_mod(m, [&]() {
base t = random::rng();
auto f = [&](auto x) {
return x * x + t;
};
base x, y;
base g = 1;
while(g == 1) {
for(int i = 0; i < 64; i++) {
x = f(x);
y = f(f(y));
if(x == y) [[unlikely]] {
t = random::rng();
x = y = 0;
} else {
base t = g * (x - y);
g = t == 0 ? g : t;
}
}
g = std::gcd(g.getr(), m);
}
factorize(g.getr(), res);
factorize(m / g.getr(), res);
});
}
}
std::vector<int64_t> factorize(int64_t m) {
std::vector<int64_t> res;
factorize(m, res);
return res;
}
int64_t primitive_root(int64_t p) {
using base = dynamic_modint;
return base::with_mod(p, [p](){
base t = 1;
while(period(t) != p - 1) {
t = random::rng();
}
return t.getr();
});
}
}
#line 6 "verify/number_theory/primitive_root.test.cpp"
#include <bits/stdc++.h>
using namespace std;
using namespace cp_algo;
using namespace math;
using base = dynamic_modint;
void solve() {
int64_t p;
cin >> p;
cout << primitive_root(p) << "\n";
}
signed main() {
//freopen("input.txt", "r", stdin);
ios::sync_with_stdio(0);
cin.tie(0);
int t = 1;
cin >> t;
while(t--) {
solve();
}
}
Env | Name | Status | Elapsed | Memory |
---|---|---|---|---|
g++ | 223092870x_plus_1_00 |
![]() |
27 ms | 3 MB |
g++ | example_00 |
![]() |
5 ms | 3 MB |
g++ | example_01 |
![]() |
5 ms | 3 MB |
g++ | large_least_primitive_root_00 |
![]() |
21 ms | 3 MB |
g++ | less_1000000000_00 |
![]() |
8 ms | 3 MB |
g++ | less_1000000000_01 |
![]() |
8 ms | 3 MB |
g++ | less_1000000000_02 |
![]() |
8 ms | 3 MB |
g++ | random_00 |
![]() |
20 ms | 3 MB |
g++ | random_01 |
![]() |
18 ms | 3 MB |
g++ | random_02 |
![]() |
15 ms | 3 MB |
g++ | safe_prime_00 |
![]() |
8 ms | 3 MB |
g++ | small_00 |
![]() |
6 ms | 3 MB |
g++ | small_01 |
![]() |
6 ms | 3 MB |
g++ | small_02 |
![]() |
7 ms | 3 MB |