對於大整數而言,要找出其因子是比較困難的,事實上仍然沒有很好的解決方法。不過在ACM裏面有幾種“標準的”方法可以使用,例如Pollard-Rho方法。
假設題目是求
一般做法是生成一個數列
注意到如果找到
POJ1811要求判斷給定數是否爲質數,如果是合數則輸出最小的質因子。先用Miller_Rabin方法判質數,然後對合數遞歸分解因子求出最小即可。
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long llt;
int const Repeat = 10;
//利用二進制計算a*b%mod
llt multiMod(llt a,llt b,llt mod){
llt ret = 0LL;
a %= mod;
while( b ){
if ( b & 1LL ) ret = ( ret + a ) % mod, --b;
b >>= 1LL;
a = ( a + a ) % mod;
}
return ret;
}
//計算a^b%mod
llt powerMod(llt a,llt b,llt mod){
llt ret = 1LL;
a %= mod;
while( b ){
if ( b & 1LL ) ret = multiMod(ret,a,mod),--b;
b >>= 1LL;
a = multiMod(a,a,mod);
}
return ret;
}
//Miller-Rabin測試,測試n是否爲素數
bool Miller_Rabin(llt n,int repeat){
if ( 2LL == n || 3LL == n ) return true;
if ( !( n & 1LL ) ) return false;
//將n分解爲2^s*d
llt d = n - 1LL;
int s = 0;
while( !( d & 1LL ) ) ++s, d>>=1LL;
//srand((unsigned)time(0));
for(int i=0;i<repeat;++i){//重複repeat次
llt a = rand() % ( n - 3 ) + 2;//取一個隨機數,[2,n-1)
llt x = powerMod(a,d,n);
llt y = 0LL;
for(int j=0;j<s;++j){
y = multiMod(x,x,n);
if ( 1LL == y && 1LL != x && n-1LL != x ) return false;
x = y;
}
if ( 1LL != y ) return false;
}
return true;
}
llt Fac[100];//質因數分解結果(剛返回時是無序的)
int FCnt;//質因數的個數。數組小標從0開始
llt gcd(llt a,llt b){
if (0L == a || 0L == b) return 1;
if ( a < 0 ) a = -a;
if ( b < 0 ) b = -b;
while(b){
llt t = a % b;
a = b;
b = t;
}
return a;
}
llt Pollard_Rho(llt n,llt c){
llt i = 1, k = 2;
llt x = rand() % n;
llt y = x;
while(1){
++i;
x = ( multiMod(x,x,n) + c ) % n;
llt d = gcd(y-x,n);
if (d!=1LL && d!=n) return d;
if (y == x) return n;
if ( i == k ) y = x, k <<= 1;
}
}
void find(llt n){
if ( 4LL == n ){
Fac[0] = Fac[1] = 2LL;
FCnt = 2;
return;
}
if ( Miller_Rabin(n,Repeat) ){
Fac[FCnt++] = n;
return;
}
llt p;
while( ( p = Pollard_Rho(n,rand()%(n-3)+3) ) == n );
find(p);
find(n/p);
}
int main(){
int kase;
scanf("%d",&kase);
while(kase--){
llt n;
scanf("%I64d",&n);
FCnt=0;
find(n);
if(Fac[0] == n) printf("Prime\n");
else printf("%I64d\n",*min_element(Fac,Fac+FCnt));
}
return 0;
}