Skip to content

Commit 966509a

Browse files
committed
feat: Add primitive root implementation and corresponding test cases
1 parent 28c3af7 commit 966509a

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

test/primitive_root.test.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#define PROBLEM "https://judge.yosupo.jp/problem/primitive_root"
2+
3+
#include "../weilycoder/number-theory/primitive_root.hpp"
4+
#include <iostream>
5+
using namespace std;
6+
using namespace weilycoder;
7+
8+
int main() {
9+
cin.tie(nullptr)->sync_with_stdio(false);
10+
cin.exceptions(cin.failbit | cin.badbit);
11+
size_t t;
12+
cin >> t;
13+
while (t--) {
14+
uint64_t p;
15+
cin >> p;
16+
cout << prime_primitive_root<>(p) << '\n';
17+
}
18+
return 0;
19+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#ifndef WEILYCODER_NUMBER_THEORY_PRIMITIVE_ROOT_HPP
2+
#define WEILYCODER_NUMBER_THEORY_PRIMITIVE_ROOT_HPP
3+
4+
#include "factorize.hpp"
5+
#include "mod_utility.hpp"
6+
#include <array>
7+
#include <cstdint>
8+
#include <vector>
9+
10+
namespace weilycoder {
11+
/**
12+
* @brief Check if g is a primitive root modulo p
13+
* @tparam N The size of the factors array
14+
* @tparam bit32 Whether to use 32-bit modular multiplication
15+
* @param g The candidate primitive root
16+
* @param p The prime modulus
17+
* @param factors The prime factors of p - 1
18+
* @return true if g is a primitive root modulo p, false otherwise
19+
*/
20+
template <size_t N = 64, bool bit32 = false>
21+
constexpr bool is_primitive_root(uint64_t g, uint64_t p,
22+
const std::array<uint64_t, N> &factors) {
23+
for (size_t i = 0; i < N; ++i) {
24+
uint64_t q = factors[i];
25+
if (q == 0)
26+
break;
27+
if (fast_power_64<bit32>(g, (p - 1) / q, p) == 1)
28+
return false;
29+
}
30+
return true;
31+
}
32+
33+
/**
34+
* @brief Check if g is a primitive root modulo p
35+
* @tparam bit32 Whether to use 32-bit modular multiplication
36+
* @param g The candidate primitive root
37+
* @param p The prime modulus
38+
* @param factors The prime factors of p - 1
39+
* @return true if g is a primitive root modulo p, false otherwise
40+
*/
41+
template <bool bit32 = false>
42+
bool is_primitive_root(uint64_t g, uint64_t p, const std::vector<uint64_t> &factors) {
43+
const size_t N = factors.size();
44+
for (size_t i = 0; i < N; ++i) {
45+
uint64_t q = factors[i];
46+
if (q == 0)
47+
break;
48+
if (fast_power_64<bit32>(g, (p - 1) / q, p) == 1)
49+
return false;
50+
}
51+
return true;
52+
}
53+
54+
/**
55+
* @brief Find a primitive root modulo a prime p
56+
* @tparam bit32 Whether to use 32-bit modular multiplication
57+
* @param p The prime modulus
58+
* @return A primitive root modulo p, or 0 if p is not prime
59+
*/
60+
template <bool bit32 = false> constexpr uint64_t prime_primitive_root(uint64_t p) {
61+
if (p == 2)
62+
return 1;
63+
if (!is_prime(p))
64+
return 0;
65+
auto factors = factorize_fixed<64, bit32>(p - 1);
66+
for (uint64_t g = 2; g < p; ++g)
67+
if (is_primitive_root<64, bit32>(g, p, factors))
68+
return g;
69+
return 0;
70+
}
71+
} // namespace weilycoder
72+
73+
#endif

0 commit comments

Comments
 (0)