题意:
给出一个数n,判断n是否为素数,如果n不是素数输出n的最小素因子…(多组数据,n<=2^54)
分析:
MillerRabin素性测试+PollardRho椭圆曲线分解法
算法讲解
Notice:
- 两数相乘可能会爆 long long,所以要自己手写乘法
代码如下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
long long Min;
inline long long random(long long n){
return ((double)rand()/RAND_MAX*n+0.5);
}
inline long long multiply(long long a,long long b,long long mod){
long long ans=0;
while(b){
if(b&1)
b--,ans=(ans+a)%mod;
else
b>>=1,a=(a*2)%mod;
}
return ans;
}
inline long long power(long long a,long long b,long long mod){
long long ans=1;
while(b){
if(b&1)
ans=multiply(ans,a,mod)%mod;
a=multiply(a,a,mod)%mod,b>>=1;
}
return ans;
}
inline bool check(long long a,long long n){
long long d=n-1;
while(!(d&1))
d>>=1;
long long t=power(a,d,n);
while(d!=n-1&&t!=n-1&&t!=1)
t=multiply(t,t,n)%n,d<<=1;
return t==n-1||d&1;
}
inline bool MillerRabin(long long n){
if(n==2)
return true;
if(n<2||!(n&1))
return false;
for(int i=1;i<=10;i++)
if(!check(random(n-2)+1,n))
return false;
return true;
}
inline long long gcd(long long x,long long y){
return y==0?x:gcd(y,x%y);
}
inline long long PollardRho(long long n,int c){
long long x,y,d,i=1,k=2;
x=random(n-2)+1,y=x;
while(1){
i++;x=(multiply(x,x,n)+c)%n;d=gcd(y-x,n);
if(1<d&&d<n)
return d;
if(y==x)
return n;
if(i==k)
y=x,k<<=1;
}
}
inline void find(long long n,int c){
if(n==1)
return;
if(MillerRabin(n)){
Min=min(Min,n);
return;
}
long long p=n;
while(p>=n)
p=PollardRho(p,c--);
find(p,c);find(n/p,c);
}
signed main(void){
int cas;long long n;
scanf("%d",&cas);
while(cas--){
scanf("%lld",&n);
Min=n;
if(MillerRabin(n))
puts("Prime");
else
find(n,12312),cout<<Min<<endl;
}
return 0;
}
by >_< NeighThorn