解决本题基于以下两步:
—>1.素数判定(Miller-Rho)
由费马小定理 a^(p-1) % p=1 (其中p为质数) 可以随机取一个a,计算上式的结果是否为1而判断p是否为素数。
值得注意的是,通过上述方法正确率只有50%,解决方法是选择20个不同 的a只要有一个不满足上式,则可以判定p不是质数。
—>2.分解质因数(Pollar-Rho)
随机选取1<x,y<n,判断t=gcd(|x-y|,n)是否为1:
若不是则t为n的一个因数,递归分解t,n/t,并判断是否已分解为质数(经过实践与理论证明|x-y|比x更不容易与n互质^_^);
若互质,x=(x^2+c)%n,可以知道一段时间后x必定会出现循环节,那么用y来判断x是否已经重复,k每次<<1来枚举循环节的长度。
如果出现了循环的话,则更换c值,重新随机选取x。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
LL mult(LL a,LL b,LL n){
LL ret=0;
while(b){
if(b&1LL) ret=(ret+a)%n;
a=(a+a)%n;
b>>=1;
}
return ret;
}
LL pow(LL a,LL u,LL n){
LL ret=1;
while(u){
if(u&1LL) ret=mult(ret,a,n);
a=mult(a,a,n);
u>>=1;
}
return ret;
}
LL gcd(LL a,LL b){
if(b==0) return a;
return gcd(b,a%b);
}
LL x[100];
bool isprime(LL n){
if(n==2) return true;
int t=0,cnt=20;
LL u=n-1;
while(!(u&1)){
t++;
u>>=1;
}
while(cnt--){
LL a=rand()%(n-2)+2;
x[0]=pow(a,u,n);
for(LL i=1;i<=t;i++){
x[i]=mult(x[i-1],x[i-1],n);
if(x[i]==1 && x[i-1]!=1 && x[i-1]!=n-1) return false;
}
if(x[t]!=1) return false;
}
return true;
}
LL devision(LL n,int c){
LL i=1;
LL x=rand()%(n-1)+1;
LL y=x;
LL k=2;
while(1){
i++;
x=(mult(x,x,n)+c)%n;
LL tmp=gcd((y-x+n)%n,n);
if(tmp!=1 && tmp!=n) return tmp;
if(x==y) return n;
if(i==k){
y=x;
k<<=1;
}
}
}
LL ans;
void find(LL n,int c){
if(n==1) return;
if(isprime(n)){
ans=min(ans,n);
return;
}
LL p=n,k=c;
while(p==n) p=devision(p,c--);
find(p,k);
find(n/p,k);
}
int main(){
LL n,i;
int t;
scanf("%d",&t);
while(t--){
ans=1LL<<62;
scanf("%lld",&n);
find(n,120);
if(ans==n) printf("Prime\n");
else printf("%lld\n",ans);
}
return 0;
}