http://poj.org/problem?id=1811
Pollard Rho 跟 Miller Rabin 的合併算法
Miller Rabin 算法:用於快速檢查一個數字是不是質數
假設我們現在在檢查p。
若p是質數,根據費馬小定理,對於每個a,a ^ p === a (mod p)。
兩邊同除a (就自行想像一下吧XDD),可能a ^ (p-1) === 1 (mod p)。
其中,若x ^ y === 1,x合理的解就只有可能是 +1 或 -1。
所以,可以發現,a ^ ( (p-1)/2 ), a ^ ( ( (p-1)/2 )/2 ), .......,只要是1 或 -1,那這個數字可能就是質數!
複雜度是好的 O(lg N)。
接下來介紹 Pollard Rho 算法,這個算法可以求出一個整數x的因數們。
在進入Pollard Rho算法之前,先用Miller Rabin判斷這個x是不是質數。
如果不是質數的話,我們先定義一個亂數生成函數f(x) = a*x^2 + c。
接著,選擇任意一個開始值s,並且令 f1 = f(s), f2 = f( f(s) )
之後,如果在某個時刻,f2和f1的差和x的最大公因數不是1 , 那我們就找到一個因數了,遞迴下去求解。
如果在某個時候,f1跟f2一樣了,我們就在換一個起始點 & 生成函數的a跟c值。
要不然,執行f1 = f(f1), f2 = f( f(f2) ),相當於是f1往前走一步,f2往前走兩步
數學家告訴我們,這樣做的話,複雜度大約只有O(N ^ (1/4))
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <utility>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <cassert>
#include <iomanip>
#include <bitset>
using namespace std;
typedef long long LL;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<LL,LL> pLL;
typedef vector<int> vint;
typedef vector<LL> vLL;
typedef vector<pii> vpii;
typedef vector<pLL> vpLL;
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()
#define F first
#define S second
#define MP make_pair
#define PB push_back
#define Si(x) scanf("%d",&(x));
#define Sii(x,y) scanf("%d %d",&(x),&(y));
#define Siii(x,y,z) scanf("%d %d %d",&(x),&(y),&(z));
#define Siiii(x,y,z,w) scanf("%d %d %d %d",&(x),&(y),&(z),&(w));
#define Siiiii(x,y,z,w,a) scanf("%d %d %d %d %d",&(x),&(y),&(z),&(w),&(a));
#define Siiiiii(x,y,z,w,a,b) scanf("%d %d %d %d %d %d",&(x),&(y),&(z),&(w),&(a),&(b));
#define SL(x) scanf("%lld",&(x));
#define SLL(x,y) scanf("%lld %lld",&(x),&(y));
#define SLLL(x,y,z) scanf("%lld %lld %lld",&(x),&(y),&(z));
#define SLLLL(x,y,z,w) scanf("%lld %lld %lld %lld",&(x),&(y),&(z),&(w));
#define SLLLLL(x,y,z,w,a) scanf("%lld %lld %lld %lld %lld",&(x),&(y),&(z),&(w),&(a));
#define SLLLLLL(x,y,z,w,a,b) scanf("%lld %lld %lld %lld %lld %lld",&(x),&(y),&(z),&(w),&(a),&(b));
#define Pi(x) printf("%d\n",(x));
#define Pii(x,y) printf("%d %d\n",(x),(y));
#define Piii(x,y,z) printf("%d %d %d\n",(x),(y),(z));
#define Piiii(x,y,z,w) printf("%d %d %d %d\n",(x),(y),(z),(w));
#define Piiiii(a,b,c,d,e) printf("%d %d %d %d %d\n",(a),(b),(c),(d),(e));
#define Piiiiii(a,b,c,d,e,f) printf("%d %d %d %d %d %d\n",(a),(b),(c),(d),(e),(f));
#define PL(x) printf("%lld\n",(x)*1LL);
#define PLL(x,y) printf("%lld %lld\n",(x)*1LL,(y)*1LL);
#define PLLL(x,y,z) printf("%lld %lld %lld\n",(x)*1LL,(y)*1LL,(z)*1LL);
#define PLLLL(x,y,z,w) printf("%lld %lld %lld %lld\n",(x)*1LL,(y)*1LL,(z)*1LL,(w)*1LL);
#define PLLLLL(a,b,c,d,e) printf("%lld %lld %lld %lld %lld\n",(a)*1LL,(b)*1LL,(c)*1LL,(d)*1LL,(e)*1LL);
#define PLLLLLL(a,b,c,d,e,f) printf("%lld %lld %lld %lld %lld %lld\n",(a)*1LL,(b)*1LL,(c)*1LL,(d)*1LL,(e)*1LL,(f)*1LL);
#define Pi1(x) printf("%d", (x));
#define PL1(x) printf("%lld",(x));
#define Pspace putchar(' ');
#define Pendl puts("");
#define MEM0(x) memset( (x), 0, sizeof( (x) ) )
#define MEM1(x) memset( (x),-1, sizeof( (x) ) )
#define REP1(i,n) for (int i = 1; (n) >= i ; ++i)
#define REP0(i,n) for (int i = 0; (n) > i ; ++i)
#define IOS ios::sync_with_stdio(0); cin.tie(0);
void Parr(int *arr,int L,int R) {
for (int i=L;R>=i;i++) {
printf("%d%c",arr[i]," \n"[i==R]);
}
}
void Pvec(vint v) {
for (int i=0;SZ(v)>i;i++) {
printf("%d%c",v[i]," \n"[i==SZ(v)-1]);
}
}
void Sarr(int *arr,int L,int R) {
for (int i=L;R>=i;i++)
{
Si(arr[i]);
}
}
//#define
LL addd(LL a,LL b,LL mod)
{
return ((a)+(b)>=(mod))?(a)+(b)-(mod):(a)+(b);
}
const int G = (1LL<<31)-1;
LL mull(LL a,LL b,LL mod)
{
if (a<G && b<G) return a*b%mod;
LL ret = 0;
LL now = a;
while (b)
{
if (b&1) ret = addd(ret,now,mod);
now = addd(now,now,mod);
b>>=1;
}
return ret;
}
LL ppow(LL a,LL n,LL mod)
{
LL ret = 1;
LL now = a;
while (n)
{
if (n&1) ret = mull(ret,now,mod);
now = mull(now,now,mod);
n>>=1;
}
return ret;
}
LL gcd(LL a,LL b)
{
if (b==0) return a;
else return gcd(b,a%b);
}
const bool PRIME = 1, COMPOSITE = 0;
bool miller_rabin(LL n,LL a)
{
if (gcd(n,a) == n) return PRIME;
else if (gcd(n,a) != 1) return COMPOSITE;
LL d=n-1,r=0;
while (d%2==0)
{
d >>= 1;
++r;
}
LL ret = ppow(a,d,n);
if (ret == 1 || ret == n-1) return PRIME;
while (r--)
{
ret = mull(ret,ret,n);
if (ret == n-1) return PRIME;
}
return COMPOSITE;
}
bool isPrime(LL n)
{
LL as[7] = {2,325,9375,28178,450775,9780504,1795265022};
for (int i=0;7>i;++i)
{
//cout<<"i = "<<i<<endl;
if (miller_rabin(n,as[i]) == COMPOSITE) return COMPOSITE;
}
return PRIME;
}
const LL C=2934852462451LL;
const LL D=126871905557494LL;
LL rnd=98134513458734897LL;
LL myRnd()
{
return rnd = (rnd + C)^D;
}
LL a,c;
LL doo(LL x,LL n)
{
return addd( mull( a, mull(x,x,n),n ),c ,n);
}
#define aabs(x) (x)>=0?(x):-(x)
LL solve(LL n)
{
if (isPrime(n)) return n;
if (!(n&1)) return 2;
a=myRnd()%n;
if (!a) a=1;
c=myRnd()%n;
//cout<<"a = "<<a<<" , c = "<<c<<endl;
while (c == 0 || c==2) c=myRnd()%n;
LL start = myRnd()%n;
//cout<<"start = "<<start<<" , ";
LL s1=doo(start,n);//cout<<"s1 = "<<s1<<endl;
LL s2=doo(s1,n);
//cout<<"n = "<<n<<" : ";
while (true)
{
if (s1 == s2)
{
start = myRnd()%n;
//a=myRnd()+1;
a=myRnd()%n;
if (!a) a=1;
c=myRnd()%n;
while (c == 0 || c==2) c=myRnd()%n;
s1 = doo(start,n);
s2 = doo(s1,n);
continue;
}
//cout<<"s1 = "<<s1<<" , s2 = "<<s2<<endl;
LL _=gcd(aabs(s1-s2),n);
if (_ != 1)
{
return min(solve(_),solve(n/_));
}
s1 = doo(s1,n);
s2 = doo(s2,n);
s2 = doo(s2,n);
}
}
int main () {
//srand(time(NULL));
int T;
Si(T);
while (T--)
{
LL n;
SL(n);
if (isPrime(n))
{
puts("Prime");
}
else
{
PL(solve(n));
}
}
}