cai_lw's competitive programming library
 
Loading...
Searching...
No Matches
factor.hpp
1#pragma once
2
3#include <algorithm>
4#include <limits>
5#include <vector>
6
7#include "cplib/num/mmint.hpp"
8#include "cplib/num/prime.hpp"
9#include "cplib/port/bit.hpp"
10
11namespace cplib {
12
13namespace impl {
14
15template <typename T>
16struct FactorizationResult {
17 std::vector<T> factors, prime_factors;
18};
19
20// https://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf
21template <typename ModInt>
22typename ModInt::int_type pollard_rho_modint() {
23 using T = typename ModInt::int_type;
24 const T n = ModInt::mod();
25 constexpr T m = std::numeric_limits<T>::digits;
26 T r = 1, g;
27 ModInt c(0), y, q, x, ys;
28 do {
29 ++c;
30 y = ModInt(2);
31 q = ModInt(1);
32 g = 1;
33 do {
34 x = y;
35 for (T i = 0; i < r; i++) {
36 y = y * y + c;
37 }
38 ys = y;
39 for (T i = 0; i < r; i++) {
40 y = y * y + c;
41 q *= y - x;
42 if ((i + 1) % m == 0) {
43 g = gcd(q.val(), n);
44 if (g != 1) {
45 break;
46 }
47 ys = y;
48 }
49 }
50 if (g == 1 && r % m != 0) {
51 g = gcd(q.val(), n);
52 }
53 r *= 2;
54 } while (g == 1);
55 if (g == n) {
56 do {
57 ys = ys * ys + c;
58 g = gcd((ys - x).val(), n);
59 } while (g == 1);
60 }
61 } while (g == n);
62 return g;
63}
64
65template <typename T>
66void factorize_work(FactorizationResult<T>& result) {
67 T n = result.factors.back();
68 result.factors.pop_back();
69 T f = prime_or_factor(n);
70 if (f == 1) {
71 result.prime_factors.push_back(n);
72 return;
73 }
74 if (f == 0) {
75 if (n < (1ull << 32)) {
76 f = mmint_by_modulus([](auto mint) { return pollard_rho_modint<decltype(mint)>(); }, uint32_t(n));
77 } else {
78 f = mmint_by_modulus([](auto mint) { return pollard_rho_modint<decltype(mint)>(); }, n);
79 }
80 }
81 result.factors.push_back(f);
82 result.factors.push_back(n / f);
83}
84
85} // namespace impl
86
99template <typename T, std::enable_if_t<std::is_unsigned_v<T>>* = nullptr>
100std::vector<T> factorize(T n) {
101 if (n <= 1) {
102 return {};
103 }
104 int twos = port::countr_zero(n);
105 impl::FactorizationResult<T> result;
106 result.prime_factors.insert(result.prime_factors.end(), twos, 2);
107 if (port::has_single_bit(n)) {
108 return result.prime_factors;
109 }
110 result.factors.push_back(n >> twos);
111 while (!result.factors.empty()) {
112 impl::factorize_work(result);
113 }
114 std::sort(result.prime_factors.begin(), result.prime_factors.end());
115 return result.prime_factors;
116}
117
118} // namespace cplib
std::vector< T > factorize(T n)
Integer factorization.
Definition: factor.hpp:100
constexpr T gcd(T x, T y)
Greatest common divisor.
Definition: gcd.hpp:21
T prime_or_factor(T n)
Primality test and possibly return a non-trivial factor.
Definition: prime.hpp:123