This documentation is automatically generated by online-judge-tools/verification-helper
This project is maintained by tsutaj
// ・ミラーラビン (高速な素数判定) // ・ロー法 (高速な素因数分解) // ・どちらも確率的なアルゴリズムであるため、小さいものは通常の素数判定で処理したほうが確実 // Verified: POJ 2429 (GCD & LCM Inverse) int gcd(int a, int b) { assert(a >= 0 && b >= 0); if(a < b) swap(a, b); return (b == 0 ? a : gcd(b, a%b)); } // 小さい数字は通常通りの素数判定で処理する (高速化のため) const int MAX_PRIME = 300000; const int MINI_PRIME = 40; bool is_prime[MAX_PRIME + 10]; vector<int> primes, mini_primes; void init_primes() { fill(is_prime, is_prime + MAX_PRIME + 10, true); is_prime[0] = is_prime[1] = false; for(int i=0; i<=MAX_PRIME; i++) { if(is_prime[i]) { if(i < MINI_PRIME) mini_primes.push_back(i); primes.push_back(i); for(int k=i+i; k<=MAX_PRIME; k+=i) { is_prime[k] = false; } } } } // ミラーラビン素数判定法 (Miller-Rabin Primality Test) // 普通に掛け算するとオーバーフローで死ぬため、バイナリ法で処理 template<typename T> struct MLPT { MLPT() {} T mod_mul(T a, T b, T mod) { T res = 0; a %= mod; while(b) { if(b & 1) (res += a) %= mod; a = (a + a) % mod; b >>= 1; } return res; } T mod_pow(T x, T n, T mod) { x %= mod; if(n == 0) return 1; T res = mod_pow(mod_mul(x, x, mod), n / 2, mod); if(n & 1) res = mod_mul(res, x, mod); return res; } // 小さい数なら素数判定テーブルをそのまま使う // 大きければしょうがないのでミラーラビンで bool solve(T N) { if(N <= MAX_PRIME) return is_prime[N]; for(size_t i=0; i<mini_primes.size(); i++) { T a = mini_primes[i]; if(N == a) return true; if(N % a == 0) return false; T d = N-1, s = 0; while(d % 2 == 0) d >>= 1, s++; if(mod_pow(a, d, N) == 1) continue; bool pbprime = false; for(int r=0; r<s; r++) { if(mod_pow(a, d*(1LL << r), N) == N-1) { pbprime = true; break; } } if(!pbprime) return false; } return true; } }; // ロー法による素因数分解 // 対象となる数が素数の場合は常に failure -> Miller Rabin と併用しよう template<typename T> struct Rho { vector<int> pat; Rho() {} MLPT<T> ml; T func(T x, T c, T mod) { return (ml.mod_mul(x, x, mod) + c) % mod; } T check(T N, int c) { T x = 2, y = 2, d = 1; while(d == 1) { x = func(x, c, N); y = func(func(y, c, N), c, N); d = gcd((x-y>0 ? x-y : y-x), N); } return (d == N ? check(N, c+1) : d); } // ソートされてないので、必要だったら別途ソートしてね vector<T> factor(T N) { if(N < 2) return vector<T>(); if(ml.solve(N)) return vector<T>(1, N); vector<T> res; // 小さい素因数は普通に素因数分解 for(size_t i=0; i<primes.size(); i++) { T a = primes[i]; if(a > N) break; while(N % a == 0) { res.push_back(a); N /= a; } } // 残ったやつはしょうがないのでロー法で if(N != 1) { if(ml.solve(N)) res.push_back(N); else { T D = check(N, 1); vector<T> va = factor(D), vb = factor(N / D); res.insert(res.end(), va.begin(), va.end()); res.insert(res.end(), vb.begin(), vb.end()); } } return res; } };
#line 1 "math/math_008_miller_rabin_rho.cpp" // ・ミラーラビン (高速な素数判定) // ・ロー法 (高速な素因数分解) // ・どちらも確率的なアルゴリズムであるため、小さいものは通常の素数判定で処理したほうが確実 // Verified: POJ 2429 (GCD & LCM Inverse) int gcd(int a, int b) { assert(a >= 0 && b >= 0); if(a < b) swap(a, b); return (b == 0 ? a : gcd(b, a%b)); } // 小さい数字は通常通りの素数判定で処理する (高速化のため) const int MAX_PRIME = 300000; const int MINI_PRIME = 40; bool is_prime[MAX_PRIME + 10]; vector<int> primes, mini_primes; void init_primes() { fill(is_prime, is_prime + MAX_PRIME + 10, true); is_prime[0] = is_prime[1] = false; for(int i=0; i<=MAX_PRIME; i++) { if(is_prime[i]) { if(i < MINI_PRIME) mini_primes.push_back(i); primes.push_back(i); for(int k=i+i; k<=MAX_PRIME; k+=i) { is_prime[k] = false; } } } } // ミラーラビン素数判定法 (Miller-Rabin Primality Test) // 普通に掛け算するとオーバーフローで死ぬため、バイナリ法で処理 template<typename T> struct MLPT { MLPT() {} T mod_mul(T a, T b, T mod) { T res = 0; a %= mod; while(b) { if(b & 1) (res += a) %= mod; a = (a + a) % mod; b >>= 1; } return res; } T mod_pow(T x, T n, T mod) { x %= mod; if(n == 0) return 1; T res = mod_pow(mod_mul(x, x, mod), n / 2, mod); if(n & 1) res = mod_mul(res, x, mod); return res; } // 小さい数なら素数判定テーブルをそのまま使う // 大きければしょうがないのでミラーラビンで bool solve(T N) { if(N <= MAX_PRIME) return is_prime[N]; for(size_t i=0; i<mini_primes.size(); i++) { T a = mini_primes[i]; if(N == a) return true; if(N % a == 0) return false; T d = N-1, s = 0; while(d % 2 == 0) d >>= 1, s++; if(mod_pow(a, d, N) == 1) continue; bool pbprime = false; for(int r=0; r<s; r++) { if(mod_pow(a, d*(1LL << r), N) == N-1) { pbprime = true; break; } } if(!pbprime) return false; } return true; } }; // ロー法による素因数分解 // 対象となる数が素数の場合は常に failure -> Miller Rabin と併用しよう template<typename T> struct Rho { vector<int> pat; Rho() {} MLPT<T> ml; T func(T x, T c, T mod) { return (ml.mod_mul(x, x, mod) + c) % mod; } T check(T N, int c) { T x = 2, y = 2, d = 1; while(d == 1) { x = func(x, c, N); y = func(func(y, c, N), c, N); d = gcd((x-y>0 ? x-y : y-x), N); } return (d == N ? check(N, c+1) : d); } // ソートされてないので、必要だったら別途ソートしてね vector<T> factor(T N) { if(N < 2) return vector<T>(); if(ml.solve(N)) return vector<T>(1, N); vector<T> res; // 小さい素因数は普通に素因数分解 for(size_t i=0; i<primes.size(); i++) { T a = primes[i]; if(a > N) break; while(N % a == 0) { res.push_back(a); N /= a; } } // 残ったやつはしょうがないのでロー法で if(N != 1) { if(ml.solve(N)) res.push_back(N); else { T D = check(N, 1); vector<T> va = factor(D), vb = factor(N / D); res.insert(res.end(), va.begin(), va.end()); res.insert(res.end(), vb.begin(), vb.end()); } } return res; } };