Miller_Rabin&Pollared_Rho

#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} ap1≡1(mod p),当p为质数的时候。
在费马小定理被证明出来的很长一段时间内,人们都认为费马小定理的逆定理是正确的,即如果 2 p − 1 2^{p-1} 2p1≡1(mod p),那么就认为p是个质数,但其实341就是一个反例,这种我们成为强伪素数的数可以把这种判定方法轻松卡掉。
但是我们发现了这样一个事情,我们称为二次探测定理

如果 x 2 ≡ 1 x^2≡1 x21(mod p),那么也就是说 ( x + 1 ) ( x − 1 ) ≡ 0 (x+1)(x-1)≡0 (x+1)(x1)0 (mod p),又因为p是质数,所以 x + 1 x+1 x+1≡0(mod p)或者
x − 1 x-1 x1≡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 的实现过程,希望对大家有所帮助,如果有写的不对或不好的地方,欢迎评论指针,谢谢。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值