typedefunsignedlonglong ll; constint TIMES = 20; // 测试轮数
ll q_exp(ll a, ll k, ll mod) { if (!k) return1; ll ans = 1; while (k) { if (k & 1) ans = ans * a % mod; a = a * a % mod; k >>= 1; } return ans; } ll q_mul(ll a, ll b, ll mod) { if (!b) return0; ll ans = 0; while (b) { if (b & 1) ans = (ans + a) % mod; a = (a + a) % mod; b >>= 1; } return ans; }
boolwitness(ll a, ll n)// 二次探测 { ll tem = n - 1; int j = 0; while (!(tem & 1)) { tem /= 2; j++; }
ll x = q_exp(a, tem, n); if (x == 1 || x == n - 1) returntrue;
while (j--) { x = q_mul(x, x, n); if (x == n - 1) returntrue; }
returnfalse; }
boolmiller_rabin(ll p)// 随机生成a来二次探测 { if (p == 2) returntrue; if (p < 2 || !(p & 1)) returntrue; // 剪枝
for (int i = 1; i < TIMES; i++) { ll a = random(p - 1) + 1; if (!witness(a, p)) { returnfalse; } } returntrue; }
intmain() { ll n; cin>>n; miller_rabin(n)? puts("It's a prime."): puts("It's not a prime"); }
Miller-Rabin的时间主要花在了计算a ^ (p - 1) mod p上,总体时间复杂度是O(logn)。
关于最大公因数
对于最大的整数n,使得n同时是a和b的因子,则称n是a和b的最大公因数(Greatest common divisor)。
性质:gcd(a, b) * lcm(a, b) = a * b。
递归求gcd
辗转相除法,直接上代码:
1 2 3 4 5 6
typedeflonglong ll; inline ll gcd(int a, int b) { return b? gcd(b, a % b): a; }
扩展欧几里德算法(exgcd)
扩展欧几里德算法是用来解决已知a, b求解一组x, y,使它们满足: ax + by = gcd(a, b) = d的算法。
代码(接上部分代码):
1 2 3 4 5 6 7 8 9 10 11 12
ll exgcd(ll a, ll b, ll &x, ll &y) { if (!b) { x = 1; y = 0; return a; } ll r = exgcd(b, a % b, x, y); ll tem = y; y = x - a / b * y; x = tem; return r; }