关于 Miller-Rabin 与 Pollard Rho 算法
P4718
Miller_Rabin
用于检测大数素性(
对于素数
- 对于任意
a \in \lbrack 1,P) , a^{P-1} \equiv 1 \: (mod \: P)
枚举
上述即费马素性检验。
存在卡迈克尔数/费马伪素数也满足上式 (如
二次探测定理:
- 若
P 为奇素数,则x^2 \equiv 1 \: (mod \: P) 的解为x \equiv \pm 1 \: (mod \: P) .
设当前选取底数为
bool check(ll a,ll n){
ll u=n-1,t=0;
while(!(u&1))u>>=1,t++;
ll x=qpow(a,u,n);
if(x==1)return false;
for(ll i=1,tmp;i<=t;i++,x=tmp){
tmp=qmul(x,x,n);//原题需要转__int128类型
if(x!=1&&x!=n-1&&tmp==1)
return true;
}
return x!=1;
}
bool Miller_Rabin(ll n){
if(n==2)return true;
if(n<2||!(n&1))return false;
for(ll i=1;i<=Test;i++){
if(check(rd()%(n-1)+1,n))//mt19937
return false;
}
return true;
}
Miller-Rabin的错误率是
Pollard Rho
用
考虑随机函数
对于 {
基于Floyd算法的优化
数列有环存在,可以用一种Floyd的判圈方法:
设
基于Floyd判圈方法的Pollard Rho算法:
ll f(ll x,ll c,ll n){
return (qmul(x,x,n)+c)%n;
}
ll Pollard_Rho(ll n){
ll c=rd(n-1)+1;
ll t=f(0,c,n),r=f(t,c,n);
while(t!=r){
ll d=gcd(abs(t-r),n);
if(d>1)return d;
t=f(t,c,N),r=f(f(r,c,n),c,n);
}
return N;//多测保证正确性
}
路径倍增优化与乘法累积
上述优化瓶颈为
考虑倍增思想,在路径中取一段
需要规定一个样本数限制相乘个数,这里取
ll f(ll x,ll c,ll n){
return (qmul(x,x,n)+c)%n;
}
ll Pollard_Rho(ll n){
if(!(n&1))return 2;
ll x=rd()%(n-1)+1,y=x,c=rd()%(n-1)+1,ret;
for(ll i=1;;i<<=1,y=x,ret=1){
for(ll j=1;j<=i;j++){
x=f(x,c,n);
ret=qmul(ret,abs(x-y),n);
if(!(j&127)){
ll d=__gcd(ret,n);
if(d>1)return d;
}
}
ll d=__gcd(ret,n);
if(d>1)return d;
}
}
粗略大概就是这么多,放个模板代码。
#include<bits/stdc++.h>
#define ll long long
#define Test 10
using namespace std;
mt19937 rd(233);
ll read(){
ll x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return x;
}
ll qmul(ll k,ll b,ll p){
return (__int128)k*b%p;
}
ll qpow(ll k,ll b,ll p){
ll val=1;k%=p;
while(b){
if(b&1)val=qmul(val,k,p);
k=qmul(k,k,p),b>>=1;
}
return val;
}
ll T,n,ans;
bool check(ll a,ll n){
ll u=n-1,t=0;
while(!(u&1))u>>=1,t++;
ll x=qpow(a,u,n);
if(x==1)return false;
for(ll i=1,tmp;i<=t;i++,x=tmp){
tmp=qmul(x,x,n);
if(x!=1&&x!=n-1&&tmp==1)
return true;
}
return x!=1;
}
bool Miller_Rabin(ll n){
if(n==2)return true;
if(n<2||!(n&1))return false;
for(ll i=1;i<=Test;i++){
if(check(rd()%(n-1)+1,n))
return false;
}
return true;
}
ll f(ll x,ll c,ll n){
return (qmul(x,x,n)+c)%n;
}
ll Pollard_Rho(ll n){
if(!(n&1))return 2;
ll x=rd()%(n-1)+1,y=x,c=rd()%(n-1)+1,ret;
for(ll i=1;;i<<=1,y=x,ret=1){
for(ll j=1;j<=i;j++){
x=f(x,c,n);
ret=qmul(ret,abs(x-y),n);
if(!(j&127)){
ll d=__gcd(ret,n);
if(d>1)return d;
}
}
ll d=__gcd(ret,n);
if(d>1)return d;
}
}
void find(ll n){
if(n<=ans)return;
if(Miller_Rabin(n)){
ans=max(ans,n);
return;
}
ll p=n;
while(p>=n)p=Pollard_Rho(n);
while(n%p==0)n/=p;
find(p),find(n);
}
int main(){
T=read();
while(T--){
n=read();
ans=1,find(n);
if(ans==n)printf("Prime\n");
else printf("%lld\n",ans);
}
return 0;
}