typedef long long LL;
Miller_Rabin素数测试
二次探测定理
如果
p
p
p是素数,
x
x
x是小于
p
p
p的正整数,且
x
2
≡
1
(
m
o
d
p
)
x^2\equiv1\pmod p
x2≡1(modp),那么要么
x
=
1
x=1
x=1,要么
x
=
p
−
1
x=p-1
x=p−1。
解读: 因为
x
2
m
o
d
p
=
1
x^2\mod p=1
x2modp=1,即
p
∣
x
2
−
1
p|x^2-1
p∣x2−1,也即
p
∣
(
x
+
1
)
(
x
−
1
)
p|(x+1)(x-1)
p∣(x+1)(x−1)。
由于
p
p
p是素数且
x
<
p
x<p
x<p,那么只可能是
x
−
1
x-1
x−1能被
p
p
p整除(此时
x
=
1
x=1
x=1)或
x
+
1
x+1
x+1能被
p
p
p整除(此时
x
=
p
−
1
x=p-1
x=p−1)。
要测试整数
n
n
n是否为素数,若
n
n
n是素数,根据费马定理,有
a
n
−
1
m
o
d
n
=
1
a^{n-1}\mod n=1
an−1modn=1。
首先任选一个数做底数
a
a
a。
我们令
n
−
1
=
d
⋅
2
R
n-1=d\cdot 2^R
n−1=d⋅2R,其中
d
d
d是一个奇数,于是
a
n
−
1
m
o
d
n
=
(
a
d
)
2
R
m
o
d
n
=
a
d
⋅
2
R
−
1
⋅
a
d
⋅
2
R
−
1
m
o
d
n
a^{n-1}\mod n=(a^d)^{2^R}\mod n=a^{d\cdot 2^{R-1}}\cdot a^{d\cdot 2^{R-1}}\mod n
an−1modn=(ad)2Rmodn=ad⋅2R−1⋅ad⋅2R−1modn
根据二次探测定理,
a
d
⋅
2
R
−
1
m
o
d
n
a^{d\cdot 2^{R-1}}\mod n
ad⋅2R−1modn要么等于
1
1
1要么等于
n
−
1
n-1
n−1。
如果
a
d
⋅
2
R
−
1
m
o
d
n
a^{d\cdot 2^{R-1}}\mod n
ad⋅2R−1modn既不等于
1
1
1也不等于
n
−
1
n-1
n−1,
n
n
n一定不是素数,结束讨论。
如果
a
d
⋅
2
R
−
1
m
o
d
n
=
n
−
1
a^{d\cdot 2^{R-1}}\mod n=n-1
ad⋅2R−1modn=n−1,我们认为
n
n
n是素数,结束讨论。
如果
a
d
⋅
2
R
−
1
m
o
d
n
=
1
a^{d\cdot 2^{R-1}}\mod n=1
ad⋅2R−1modn=1,继续讨论:
- 根据二次探测定理, a d ⋅ 2 R − 2 m o d n a^{d\cdot 2^{R-2}}\mod n ad⋅2R−2modn要么等于 1 1 1要么等于 n − 1 n-1 n−1。……
上述讨论过程中,如果存在某个整数
k
k
k,使得
a
d
⋅
2
k
m
o
d
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),我们就认为
n
n
n是素数,结束讨论。
或者,若
a
d
m
o
d
n
=
1
a^d\mod n=1
admodn=1,
n
n
n是素数。
这是一种不确定算法,每一次测试的准确率约为
75
%
75\%
75%。
若进行了
m
m
m次测试,时间复杂度为
O
(
m
log
3
n
)
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 < 4759123141 n<4759123141 n<4759123141时,只需检测 a = 2 , 7 , 61 a=2,7,61 a=2,7,61,即可确保正确。
- n < 2152302898747 n<2152302898747 n<2152302898747时,只需检测 a = 2 , 3 , 5 , 7 , 11 a=2,3,5,7,11 a=2,3,5,7,11,即可确保正确。
- n < 341550071728320 n<341550071728320 n<341550071728320时,只需检测 a = 2 , 3 , 5 , 7 , 11 , 13 , 17 a=2,3,5,7,11,13,17 a=2,3,5,7,11,13,17,即可确保正确。
线性求逆元
a − 1 = { 1 a = 1 ( p − ⌊ p a ⌋ ) ( p m o d a ) − 1 m o d p a > 1 a^{-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
证明:
显然
1
1
1的逆元为
1
1
1。
a
>
1
a>1
a>1时,已知
a
⋅
a
−
1
≡
1
(
m
o
d
p
)
a\cdot a^{-1}\equiv 1\pmod p
a⋅a−1≡1(modp),其中
1
<
a
<
p
1<a<p
1<a<p。
令
k
=
⌊
p
a
⌋
,
r
=
p
m
o
d
a
k=\lfloor\frac pa\rfloor,r=p\mod a
k=⌊ap⌋,r=pmoda,那么
p
=
k
a
+
r
,
0
<
r
<
a
p=ka+r,0<r<a
p=ka+r,0<r<a
则有
k
a
+
r
≡
0
(
m
o
d
p
)
ka+r\equiv 0\pmod p
ka+r≡0(modp)
两边同时乘以
a
−
1
r
−
1
a^{-1}r^{-1}
a−1r−1得到
(
k
a
+
r
)
a
−
1
r
−
1
≡
0
(
m
o
d
p
)
(ka+r)a^{-1}r^{-1}\equiv 0\pmod p
(ka+r)a−1r−1≡0(modp)
即
k
⋅
r
−
1
+
a
−
1
≡
0
(
m
o
d
p
)
k\cdot r^{-1}+a^{-1}\equiv 0\pmod p
k⋅r−1+a−1≡0(modp)
转换得
a
−
1
=
−
k
⋅
r
−
1
m
o
d
p
=
−
⌊
p
a
⌋
(
p
m
o
d
a
)
−
1
m
o
d
p
=
(
p
−
⌊
p
a
⌋
)
(
p
m
o
d
a
)
−
1
m
o
d
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;
}