题意:T个数,若为素数则输出Prime,否则输出其最小的质因子。
思路:
(1)素数判定(Miller-Robin):
根据费马小定理,有:
a ^ (p - 1) % p = 1;
其中p为素数,0 < a < p。
于是我们随机生成a,验证p是否满足条件即可,为了尽量减少错误概率,可以生成多个不同的a。
(2)质因数分解(Pollard-Rho):
依旧是随机算法,设 1 < x, y < n, (x, y为随机生成)
每次判断t = gcd(|x - y|, n)是否为1, 若不是则t为n的一个因数,递归分解 t 与 n / t,并判断是否已分解为素数(研究表明,|x - y|比 x 更不容易与n互质,虽然不会证->__->);
若互质,则令x = (x * x + c) % n, 可以证明x必定会出现循环,所以用y来判断是否重复,如果出现了循环却还未找到因数,再随机出个c继续判断即可。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#define For(i,j,k) for(int i = j;i <= k;i ++)
using namespace std;
typedef long long LL;
LL Ans;
LL Mult(LL a, LL b, LL Mod){
LL s = 0;
while(b){
if(b & 1LL) s = (s + a) % Mod;
a = (a << 1) % Mod;
b >>= 1;
}
return s;
}
LL Pow(LL a, LL b, LL Mod){
LL s = 1;
while(b){
if(b & 1LL)s = Mult(s, a, Mod);
a = Mult(a, a, Mod);
b >>= 1;
}
return s;
}
LL c[60];
bool Miller_Robin(LL x){
if(x == 2)return true;
int T = 20;
LL k = 0, u = x - 1;
while(!(u & 1LL)) u >>= 1, ++k;
while(T--){
LL R = rand() % (x - 2) + 2, i = k;
c[i] = Pow(R, u, x);
while(i--){
c[i] = Mult(c[i+1], c[i+1], x);
if(c[i] == 1 && c[i+1] != 1 && c[i+1] != x - 1)
return false;
}
if(c[0] != 1)return false;
}
return true;
}
LL gcd(LL x, LL y){
return y ? gcd(y, x % y) : x;
}
LL Pollard_Rho(LL x, LL c){
LL u = rand() % (x - 1) + 1, v = u, L = 1, R = 2;
while(1){
++L;
u = (Mult(u, u, x) + c) % x;
if(u == v)return x;
LL fac = gcd((u - v + x) % x, x);
if(fac != 1 && fac != x) return fac;
if(L == R){
R <<= 1;
v = u;
}
}
}
void Findfac(LL x){
if(Miller_Robin(x)){
Ans = min(x, Ans);
return;
}
LL p = Pollard_Rho(x, rand());
while(p == x)p = Pollard_Rho(x, rand());
Findfac(p);
Findfac(x / p);
}
int main(){
int T;
LL n;
scanf("%d", &T);
while(T--){
scanf("%lld", &n);
if(Miller_Robin(n)) puts("Prime");
else{
Ans = 1LL << 60;
Findfac(n);
printf("%lld\n", Ans);
}
}
return 0;
}