M i l l e r − R a b i n Miller-Rabin Miller−Rabin模板解析
P o l l a r d − R h o Pollard-Rho Pollard−Rho模板解析
之前写了半天的Pollard-Rho在洛谷上一直过不了,后来终于找到原因了,我真是够SB的
看一下Pollard-Rho的两种实现方式,(以下所有 l l ll ll均代指 l o n g l o n g long long longlong, m u l ( a , b , c ) mul(a,b,c) mul(a,b,c)均表示在 % c \%c %c意义下的快速乘)
1.
inline ll Pollard_Rho(ll x){
ll i=1,k=2,n=rand()%(x-1)+1,m=n,c=rand()%(x-1)+1;
while(true){
++i;
n=(mul(n,n,x)+c)%x;
ll p=gcd((m-n+x)%x,x);
if(p!=1&&p!=x)return p;
if(m==n)return x;
if(i==k)k<<=1,m=n;
}
}
inline ll Pollard_Rho(ll x){
ll n=0,m=0,t=1,q=1,c=rand()%(x-1)+1;
for(ll k=2;;k<<=1,m=n,q=1){
for(ll i=1;i<=k;++i){
n=(mul(n,n,x)+c)%x;
q=mul(q,abs(m-n),x);
}
t=gcd(x,q);if(t>1)return t;
}
}
稍有常识的人就 能看出第一份是要明显慢于第二份的。因为关键操作 g c d gcd gcd次数的不同。
第一份在每次循环中都需要计算 g c d gcd gcd,而第二份只会在每次完成倍增后计算 g c d gcd gcd。期望计算次数第二份小于第一份。
感觉是期望 O ( n 1 2 ) O(n^{\frac{1}{2}}) O(n21)和期望 O ( n 1 4 ) O(n^{\frac{1}{4}}) O(n41)次计算 g c d gcd gcd的差别。
如果有计算出精确计算规模差距的读者,希望能够告知博主。
代码:
#include
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define puts put_s
#define cs const
namespace IO{
cs int Rlen=1<<18|1;
char buf[Rlen],*p1=buf,*p2=buf;
char obuf[Rlen],*p3=obuf;
inline char get_char(){
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline ll getint(){
re ll num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline void put_char(char c){
*p3++=c;
if(p3==obuf+Rlen)fwrite(obuf,1,Rlen,stdout),p3=obuf;
}
inline void put_s(cs char *s){
for(int re i=0;s[i];++i)pc(s[i]);pc('\n');
}
inline void outint(ll a){
static char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);pc('\n');
}
inline void FLUSH(){
if(p3==obuf)return ;
fwrite(obuf,1,p3-obuf,stdout);
p3=obuf;
}
}
using namespace IO;
inline ll mul(ll a,ll b,ll mod){
return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;
}
inline ll quickpow(ll a,ll b,ll mod){
re ll ans=1;
for(;b;b>>=1,a=mul(a,a,mod))if(b&1)ans=mul(ans,a,mod);
return ans;
}
cs int P=1007;
bitset<P> mark;
int prime[P],pcnt;
int maxpri[P];
inline void linear_sieves(int len=P-7){
mark[1]=true;
for(int re i=2;i<=len;++i){
if(!mark[i])prime[++pcnt]=i,maxpri[i]=i;
for(int re j=1;j<=pcnt&&i*prime[j]<=len;++j){
mark[i*prime[j]]=true;
maxpri[i*prime[j]]=maxpri[i];
if(i==i/prime[j]*prime[j])break;
}
}
}
inline bool isprime(ll x){
if(x<=P-7)return !mark[x];
if(!(x&1)||(x%3==0)||(x%5==0)||(x%7)==0||(x%61==0)||(x%24251)==0)return false;
ll t=x-1,s=0;
while(!(t&1))t>>=1,++s;
for(int re i=1;i<=5;++i){
ll p=prime[rand()%pcnt+1]%x;
ll num=quickpow(p,t,x),pre=num;
if(x%p==0)return false;
for(int re j=0;j<s;++j){
num=mul(num,num,x);
if(num==1&&pre!=1&&pre!=x-1)return false;
pre=num;
}
if(num!=1)return false;
}
return true;
}
inline ll gcd(ll a,ll b){
if(!a||!b)return a+b;
re int t=__builtin_ctzll(a|b);
a>>=__builtin_ctzll(a);
while(b){
b>>=__builtin_ctzll(b);
if(a>b)a^=b,b^=a,a^=b;
b-=a;
}
return a<<t;
}
ll ans;
inline ll Pollard_Rho(ll x){
if(x%2==0)return 2;
if(x%3==0)return 3;
if(x%5==0)return 5;
if(x%7==0)return 7;
if(x%61==0)return 61;
if(x%24251==0)return 24251;
ll n=0,m=0,t=1,q=1,c=rand()%(x-1)+1;
for(ll k=2;;k<<=1,m=n,q=1){
for(ll i=1;i<=k;++i){
n=(mul(n,n,x)+c)%x;
q=mul(q,abs(m-n),x);
}
t=gcd(x,q);if(t>1)return t;
}
}
inline void sieves(ll x){
if(x==1)return ;if(x<=ans)return ;
if(isprime(x))return (void)(ans=max(ans,x));
if(x<=P-7)return (void)(ans=max(ans,(ll)maxpri[x]));
re ll p=x;
while(p>=x)p=Pollard_Rho(p);
sieves(p);
while(x%p==0)x/=p;
sieves(x);
}
int T;
signed main(){
srand(time(0));
linear_sieves();
T=getint();
while(T--){
ll n=getint();
if(n<=P-7)mark[n]?outint(maxpri[n]):puts("Prime");
else {
ans=0;
sieves(n);
if(ans==n)puts("Prime");
else outint(ans);
}
}
FLUSH();
return 0;
}