3
3
#include " ../random/rng.hpp"
4
4
#include " affine.hpp"
5
5
#include " modint.hpp"
6
+ #include < algorithm>
6
7
#include < optional>
8
+ #include < vector>
9
+ #include < bit>
7
10
namespace cp_algo ::algebra {
8
11
// https://en.wikipedia.org/wiki/Berlekamp-Rabin_algorithm
9
12
template <modint_type base>
@@ -26,43 +29,64 @@ namespace cp_algo::algebra {
26
29
}
27
30
}
28
31
}
29
-
30
- template <modint_type base>
31
- bool is_prime_mod () {
32
- auto m = base::mod ();
32
+ // https://en.wikipedia.org/wiki/Miller–Rabin_primality_test
33
+ bool is_prime (uint64_t m) {
33
34
if (m == 1 || m % 2 == 0 ) {
34
35
return m == 2 ;
35
36
}
36
- auto m1 = m - 1 ;
37
- int d = 0 ;
38
- while (m1 % 2 == 0 ) {
39
- m1 /= 2 ;
40
- d++;
41
- }
42
- auto test = [&](auto x) {
43
- x = bpow (x, m1);
44
- if (x == 0 || x == 1 || x == -1 ) {
37
+ // m - 1 = 2^s * d
38
+ int s = std::countr_zero (m - 1 );
39
+ auto d = (m - 1 ) >> s;
40
+ using base = dynamic_modint;
41
+ auto test = [&](base x) {
42
+ x = bpow (x, d);
43
+ if (std::abs (x.rem ()) <= 1 ) {
45
44
return true ;
46
45
}
47
- for (int i = 0 ; i <= d; i++) {
48
- if (x == -1 ) {
49
- return true ;
50
- }
46
+ for (int i = 1 ; i < s && x != -1 ; i++) {
51
47
x *= x;
52
48
}
53
- return false ;
49
+ return x == - 1 ;
54
50
};
55
- for (base b: {2 , 325 , 9375 , 28178 , 450775 , 9780504 , 1795265022 }) {
56
- if (!test (b)) {
57
- return false ;
58
- }
51
+ return base::with_switched_mod (m, [&](){
52
+ // Works for all m < 2^64: https://miller-rabin.appspot.com
53
+ return std::ranges::all_of (std::array{
54
+ 2 , 325 , 9375 , 28178 , 450775 , 9780504 , 1795265022
55
+ }, test);
56
+ });
57
+ }
58
+ // https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
59
+ void factorize (uint64_t m, std::vector<int64_t > &res) {
60
+ if (m % 2 == 0 ) {
61
+ res.push_back (2 );
62
+ factorize (m / 2 , res);
63
+ } else if (is_prime (m)) {
64
+ res.push_back (m);
65
+ } else if (m > 1 ) {
66
+ uint64_t g = 1 ;
67
+ using base = dynamic_modint;
68
+ base::with_switched_mod (m, [&]() {
69
+ while (g == 1 || g == m) {
70
+ auto f = [t = random::rng ()](auto x) {
71
+ return x * x + t;
72
+ };
73
+ g = 1 ;
74
+ base x, y;
75
+ while (g == 1 ) {
76
+ x = f (x);
77
+ y = f (f (y));
78
+ g = std::gcd (m, (x - y).getr ());
79
+ }
80
+ }
81
+ });
82
+ factorize (g, res);
83
+ factorize (m / g, res);
59
84
}
60
- return true ;
61
85
}
62
- bool is_prime (int64_t m) {
63
- return dynamic_modint::with_switched_mod (m, [](){
64
- return is_prime_mod<dynamic_modint>( );
65
- }) ;
86
+ auto factorize (int64_t m) {
87
+ std::vector< int64_t > res;
88
+ factorize (m, res );
89
+ return res ;
66
90
}
67
91
}
68
92
#endif // CP_ALGO_ALGEBRA_NUMBER_THEORY_HPP
0 commit comments