typedef long long LL;
Miller_Rabin素数测试
二次探测定理
如果ppp是素数,xxx是小于ppp的正整数,且x2≡1(modp)x^2\equiv1\pmod px2≡1(modp),那么要么x=1x=1x=1,要么x=p−1x=p-1x=p−1。
解读: 因为x2mod p=1x^2\mod p=1x2modp=1,即p∣x2−1p|x^2-1p∣x2−1,也即p∣(x+1)(x−1)p|(x+1)(x-1)p∣(x+1)(x−1)。
由于ppp是素数且x<px<px<p,那么只可能是x−1x-1x−1能被ppp整除(此时x=1x=1x=1)或x+1x+1x+1能被ppp整除(此时x=p−1x=p-1x=p−1)。
要测试整数nnn是否为素数,若nnn是素数,根据费马定理,有an−1mod n=1a^{n-1}\mod n=1an−1modn=1。
首先任选一个数做底数aaa。
我们令n−1=d⋅2Rn-1=d\cdot 2^Rn−1=d⋅2R,其中ddd是一个奇数,于是an−1mod n=(ad)2Rmod n=ad⋅2R−1⋅ad⋅2R−1mod na^{n-1}\mod n=(a^d)^{2^R}\mod n=a^{d\cdot 2^{R-1}}\cdot a^{d\cdot 2^{R-1}}\mod nan−1modn=(ad)2Rmodn=ad⋅2R−1⋅ad⋅2R−1modn
根据二次探测定理, ad⋅2R−1mod na^{d\cdot 2^{R-1}}\mod nad⋅2R−1modn要么等于111要么等于n−1n-1n−1。
如果ad⋅2R−1mod na^{d\cdot 2^{R-1}}\mod nad⋅2R−1modn既不等于111也不等于n−1n-1n−1,nnn一定不是素数,结束讨论。
如果ad⋅2R−1mod n=n−1a^{d\cdot 2^{R-1}}\mod n=n-1ad⋅2R−1modn=n−1,我们认为nnn是素数,结束讨论。
如果ad⋅2R−1mod n=1a^{d\cdot 2^{R-1}}\mod n=1ad⋅2R−1modn=1,继续讨论:
- 根据二次探测定理, ad⋅2R−2mod na^{d\cdot 2^{R-2}}\mod nad⋅2R−2modn要么等于111要么等于n−1n-1n−1。……
上述讨论过程中,如果存在某个整数kkk,使得ad⋅2kmod n=n−1(0⩽k<R)a^{d\cdot 2^k}\mod n = n-1 (0\leqslant k<R)ad⋅2kmodn=n−1(0⩽k<R),我们就认为nnn是素数,结束讨论。
或者,若admod n=1a^d\mod n=1admodn=1,nnn是素数。
这是一种不确定算法,每一次测试的准确率约为75%75\%75%。
若进行了mmm次测试,时间复杂度为O(mlog3n)O(m\log_3n)O(mlog3n)。
bool miller_rabin(LL n){
if(n==2)return 1;
if(n<2||!(n%2))return 0;
LL d=n-1;int r=0;
while(!(d&1))d/=2,r++;
for(int i=1;i<=10;i++){
LL a=rand()%(n-2)+2,x=Pow(a,d,n);
for(int j=1;j<=r;j++){
LL y=Mul(x,x,n);
if(y==1&&x!=1&&x!=n-1)return 0;
x=y;
}
if(x!=1)return 0;
}
return 1;
}
一些玄学操作:
- n<4759123141n<4759123141n<4759123141时,只需检测a=2,7,61a=2,7,61a=2,7,61,即可确保正确。
- n<2152302898747n<2152302898747n<2152302898747时,只需检测a=2,3,5,7,11a=2,3,5,7,11a=2,3,5,7,11,即可确保正确。
- n<341550071728320n<341550071728320n<341550071728320时,只需检测a=2,3,5,7,11,13,17a=2,3,5,7,11,13,17a=2,3,5,7,11,13,17,即可确保正确。
线性求逆元
a−1={1a=1(p−⌊pa⌋)(pmod a)−1mod pa>1a^{-1}=\begin{cases} 1&a=1\\ (p-\lfloor\frac pa\rfloor)(p\mod a)^{-1}\mod p&a>1 \end{cases}a−1={1(p−⌊ap⌋)(pmoda)−1modpa=1a>1
证明:
显然111的逆元为111。
a>1a>1a>1时,已知a⋅a−1≡1(modp)a\cdot a^{-1}\equiv 1\pmod pa⋅a−1≡1(modp),其中1<a<p1<a<p1<a<p。
令k=⌊pa⌋,r=pmod ak=\lfloor\frac pa\rfloor,r=p\mod ak=⌊ap⌋,r=pmoda,那么p=ka+r,0<r<ap=ka+r,0<r<ap=ka+r,0<r<a
则有ka+r≡0(modp)ka+r\equiv 0\pmod pka+r≡0(modp)
两边同时乘以a−1r−1a^{-1}r^{-1}a−1r−1得到(ka+r)a−1r−1≡0(modp)(ka+r)a^{-1}r^{-1}\equiv 0\pmod p(ka+r)a−1r−1≡0(modp)
即k⋅r−1+a−1≡0(modp)k\cdot r^{-1}+a^{-1}\equiv 0\pmod pk⋅r−1+a−1≡0(modp)
转换得
a−1=−k⋅r−1mod p=−⌊pa⌋(pmod a)−1mod p=(p−⌊pa⌋)(pmod a)−1mod p\begin{aligned}
a^{-1}&=-k\cdot r^{-1}\mod p\\
&=-\lfloor\frac pa\rfloor(p\mod a)^{-1}\mod p\\
&=(p-\lfloor\frac pa\rfloor)(p\mod a)^{-1}\mod p
\end{aligned}a−1=−k⋅r−1modp=−⌊ap⌋(pmoda)−1modp=(p−⌊ap⌋)(pmoda)−1modp
时间复杂度:O(n)O(n)O(n)
void make_inv(int*inv,int n,int p){
inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=(p-p/i)*inv[p%i]%p;
}