分析:
经典题!!
数学题
miller_rabbin素数判定。若不是,则pollard_rho分解质因子,找到最小即可。
Miller-rabin
Miller-rabin算法是一个用来快速判断一个正整数是否为素数的算法。它利用了费马小定理,即:如果p是质数,且a,p互质,那么a^(p-1) mod p恒等于1。也就是对于所有小于p的正整数a来说都应该复合a^(p-1) mod p恒等于1。那么根据逆否命题,对于一个p,我们只要举出一个a(a<p)不符合这个恒等式,则可判定p不是素数。Miller-rabin算法就是多次用不同的a来尝试p是否为素数。
但是每次尝试过程中还做了一个优化操作,以提高用少量的a检测出p不是素数的概率。这个优化叫做二次探测。它是根据一个定理:如果p是一个素数,那么对于x(0<x<p),若x^2 mod p 等于1,则x=1或p-1。逆否命题:如果对于x(0<x<p),若x^2 mod p 不等于1,则p不是素数。根据这个定理,我们要计算a^(p-1) mod p是否等于1时,可以这样计算,设p-1=(2^t) * k。我们从a^k开始,不断将其平方直到得到a^(p-1),一旦发现某次平方后mod p等于1了,那么说明符合了二次探测定理的逆否命题使用条件,立即检查x是否等于1或p-1,如果不是则可直接判定p为合数。
pollard-rho
这是一个用来快速对整数进行质因数分解的算法,需要与Miller-rabin共同使用。求n的质因子的基本过程是,先判断n是否为素数,如果不是则按照一个伪随机数生成过程来生成随机数序列,对于每个生成的随机数判断与n是否互质,如果互质则尝试下一个随机数。如果不互质则将其公因子记作p,递归求解p和n/p的因子。如果n是素数则直接返回n为其素因子。
至于这个随机数序列是如何生成的暂时还不能理解,而且也是有多种不同的方式。这个序列生成过程中会产生循环,遇到循环则立即退出。
/*
题目形式:素性测试
题意:给定一个64位整数,问是否为质数,
如果不是,则输出其最小因子。
时间复杂度:难以估计
*/
typedef long long LL;
const int S = 20; //进行素性测试的循环次数
const int MAXN = 10000;
LL factor[MAXN];
int tot;
LL muti_mod(LL a,LL b,LL c){ //返回(a*b) mod c [a,b,c < 2^63]
a %= c;
b %= c;
LL ret = 0;
while(b > 0){
if(b & 1){
ret += a;
if(ret >= c) ret -=c;
}
a <<= 1;
if(a >= c) a -= c;
b >>= 1;
}
return ret;
}
LL pow_mod(LL x,LL n,LL mod){ //返回x^n mod c
LL ret = 1;
while(n > 0){
if(n&1) ret = muti_mod(ret,x,mod);
x = muti_mod(x,x,mod);
n >>= 1;
}
return ret;
}
//以a为基,n-1 = x*2^t,检验n是不是合数
bool check(LL a,LL n,LL x,LL t){
LL ret = pow_mod(a,x,n),last = ret;
for(int i = 1;i <= t;++i){
ret = muti_mod(ret,ret,n);
if(ret == 1 && last != 1 && last != n -1)
return true;
last = ret;
}
if(ret != 1) return true;
return false;
}
bool Miller_Rabin(LL n){
LL x = n - 1,t = 0;
while((x&1) == 0){x >>= 1; ++t;}
bool flag = true;
if(t >= 1 && (x&1) == 1){
for(int k = 0;k < S;++k){
LL a = rand() % (n - 1) + 1;
if(check(a,n,x,t)){flag = true;break;}
flag = false;
}
}
if(!flag || n == 2) return false;
return true;
}
LL gcd(LL a,LL b){
//a,b其一为0的时候要特判
//a,b为0最大公约数没有意义
if(a == 0) return b;
if(a < 0) return gcd(-a,b);
while(b > 0){
LL t = a % b;
a = b;
b = t;
}
return a;
}
LL Pollard_rho(LL x,LL c){
LL i = 1,x0 = rand() % x,y = x0,k = 2;
while(1){
i++;
x0 = (muti_mod(x0,x0,x) + c) % x;
LL d = gcd(y - x0,x);
if(d != 1&& d != x){
return d;
}
if(y == x0) return x;
if(i == k){
y = x0;
k += k;
}
}
}
void findfac(LL n){ //递归进行质因子数分解N
if(!Miller_Rabin(n)){
factor[tot++] = n;
return;
}
LL p = n;
while(p >= n) p = Pollard_rho(p,
rand() % (n - 1) + 1);
findfac(p);
findfac(n / p);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
LL n;
scanf("%I64d",&n);
if(!Miller_Rabin(n)){
puts("Prime");
} else {
tot = 0;
findfac(n);
LL ans = n;
for(int i = 0;i < tot;++i)
ans = min(ans,factor[i]);
printf("%I64d\n",ans);
}
}
return 0;
}