Skip to content

Commit 1a2c526

Browse files
committed
Add factorize test
1 parent 9ed82eb commit 1a2c526

File tree

4 files changed

+92
-31
lines changed

4 files changed

+92
-31
lines changed

cp-algo/algebra/modint.hpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,14 @@ namespace cp_algo::algebra {
8888
auto static with_switched_mod(int64_t tmp, auto callback) {
8989
auto prev = mod();
9090
switch_mod(tmp);
91-
auto res = callback();
92-
switch_mod(prev);
93-
return res;
91+
if constexpr(std::is_void_v<std::invoke_result_t<decltype(callback)>>) {
92+
callback();
93+
switch_mod(prev);
94+
} else {
95+
auto res = callback();
96+
switch_mod(prev);
97+
return res;
98+
}
9499
}
95100
private:
96101
static int64_t m;

cp-algo/algebra/number_theory.hpp

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
#include "../random/rng.hpp"
44
#include "affine.hpp"
55
#include "modint.hpp"
6+
#include <algorithm>
67
#include <optional>
8+
#include <vector>
9+
#include <bit>
710
namespace cp_algo::algebra {
811
// https://en.wikipedia.org/wiki/Berlekamp-Rabin_algorithm
912
template<modint_type base>
@@ -26,43 +29,64 @@ namespace cp_algo::algebra {
2629
}
2730
}
2831
}
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) {
3334
if(m == 1 || m % 2 == 0) {
3435
return m == 2;
3536
}
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) {
4544
return true;
4645
}
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++) {
5147
x *= x;
5248
}
53-
return false;
49+
return x == -1;
5450
};
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);
5984
}
60-
return true;
6185
}
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;
6690
}
6791
}
6892
#endif // CP_ALGO_ALGEBRA_NUMBER_THEORY_HPP

cp-algo/random/rng.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
#include <random>
55
namespace cp_algo::random {
66
uint64_t rng() {
7-
static std::mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
7+
static std::mt19937_64 rng(
8+
std::chrono::steady_clock::now().time_since_epoch().count()
9+
);
810
return rng();
911
}
1012
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// @brief Factorize
2+
#define PROBLEM "https://judge.yosupo.jp/problem/factorize"
3+
#pragma GCC optimize("Ofast,unroll-loops")
4+
#pragma GCC target("avx2,tune=native")
5+
#include "cp-algo/algebra/number_theory.hpp"
6+
#include <bits/stdc++.h>
7+
8+
using namespace std;
9+
using namespace cp_algo::algebra;
10+
11+
void solve() {
12+
int64_t m;
13+
cin >> m;
14+
auto res = factorize(m);
15+
ranges::sort(res);
16+
cout << size(res) << " ";
17+
ranges::copy(res, ostream_iterator<int64_t>(cout, " "));
18+
cout << "\n";
19+
}
20+
21+
signed main() {
22+
//freopen("input.txt", "r", stdin);
23+
ios::sync_with_stdio(0);
24+
cin.tie(0);
25+
int t = 1;
26+
cin >> t;
27+
while(t--) {
28+
solve();
29+
}
30+
}

0 commit comments

Comments
 (0)