#Miller_Rabin质数判断
我们朴素的质数判断算法是枚举小于等于 n \sqrt{n} n的数,判断是否都不能整除n,这样的复杂度是 n \sqrt{n} n,那么当n的数量级达到 1 0 18 10^{18} 1018的时候就不够优越了。这时候我们的Miller_Rubin算法就闪亮登场了。
我们的故事从费马小定理讲起, a p − 1 a^{p-1} ap−1≡1(mod p),当p为质数的时候。
在费马小定理被证明出来的很长一段时间内,人们都认为费马小定理的逆定理是正确的,即如果 2 p − 1 2^{p-1} 2p−1≡1(mod p),那么就认为p是个质数,但其实341就是一个反例,这种我们成为强伪素数的数可以把这种判定方法轻松卡掉。
但是我们发现了这样一个事情,我们称为二次探测定理
如果 x 2 ≡ 1 x^2≡1 x2≡1(mod p),那么也就是说 ( x + 1 ) ( x − 1 ) ≡ 0 (x+1)(x-1)≡0 (x+1)(x−1)≡0 (mod p),又因为p是质数,所以 x + 1 x+1 x+1≡0(mod p)或者
x − 1 x-1 x−1≡0(mod p),所以x mod p=1或者 x mod p=-1
那么我们有了二次探测定理,我们再来看341这个数。
2 340 2^{340} 2340%341 == 1
2 170 2^{170} 2170%341 == 1
2 85 2^{85} 285%341 == 32
这时候就出现问题了,我们就把341这个伪质数揪出来了。
我们把质数的这个序列找出来发现一定是形如1,1…1,1,1,1,p-1这样子的,p-1之后可以为无序,我们设x要判断的数,d为x去掉所有2因子之后的结果。先判断 2 d 2^{d} 2d%x为多少,然后不断地把d*2,继续判断余数。
只有出现这两种情况时我们认为x是质数
1.序列全为1
2.序列出现了p-1
我们结合代码来讲如何判断
for (int i=1;i<=t;i++){
LL d=x-1;
while (!(d&1)) d>>=1;
LL s=ksm(q[i],d,x);
while (s!=1&&s!=x-1&&d!=x-1) d<<=1,s=mul(s,s,x);
if (s!=x-1&&!(d&1)) return 0;//如果找到的是p-1则没事,如果找到的是1,(根据二次探测定理,1前面一定全是1)那么必须全为1。
}
但是这样判断并不一定完全正确,所以我们需要将2(上文中的底数)换成别的数,一般来说在long long 范围内,2,3,7,61就都够用了。
这是模板题 https://loj.ac/problem/143
#Pollared_Rho
为什么要把这两个放在一起讲呢,因为这两个算法的正确性都有那么一点瑕疵,可能算是某种相同点吧,而且Pollard_Rho中要用到Miller_Rabin。
先贴出模板题吧,求 ϕ ( n ) \phi(n) ϕ(n),n<= 1 0 18 10^{18} 1018
如果直接暴力,也是根号的。
那么我们随机一个数判断是否为n的因数,也不是很优,甚至劣于暴力。
作者对于Pollared_Rho的复杂度证明也不是很精通,这里就讲一讲做法。
每次有一个n,我们先用Miller_Rabin 判断他本身是不是质数,如果不是质数,我们先在0…n-1范围内随机一个种子seed,我们依靠这个seed来形成一个随机序列,假设这个随机序列的这一项为x,那么下一项为(x*x+seed)%n,我们每次判断这个随机序列的a,b两项做差,用这个差和n取gcd,然后进一步分解。
看代码
LL Nex(LL x,LL n){
return (mul(x,x,n)+seed)%n;//mul为慢速乘,防止乘的时候爆long long
}
void Pollared_Rho(LL n){
if (n==1) return;
if (Miller_Rubin(n)){//这里是计算phi的,具体的证明在我的博客线性求phi中有
m[n]++;//m是个map
if (m[n]==1) ans=ans*(n-1);
else ans=ans*n;
return;
}
while (1){
seed=rand()*rand()%(n-1);//先随机一个seed
LL a=rand()%(n-1),b=Nex(a,n);
while (a!=b){
LL kk=gcd(n,abs(a-b));
if (kk>1){
Pollared_Rho(kk);
Pollared_Rho(n/kk);
return;
}
a=Nex(a,n),b=Nex(Nex(b,n),n);//这里很关键,b每次都比a多走一步,如果形成环的话,b势必会追上a,这种判环的方法最为好写,是floyd这个人发明的,注意,不是我们所熟知的那个3方的判环。
}
}
}
以上就是Pollared_Rho 的实现过程,希望对大家有所帮助,如果有写的不对或不好的地方,欢迎评论指针,谢谢。