Miller-Rabin
判斷大素數的方法。
對於素數p,僅存在,使得。
任取前幾小的素數(通常前10小的素數),進行二次探測:
- 首先滿足歐拉定理
- 求出滿足,且爲奇數
- 由逐步平方若且不是,則非奇數
通過二次探測的數很大概率上爲素數。
Pollar-Pho
快速分解的所有質因子的方法:
每次找出一個的一個約數:
- 任取,設變化爲爲中任意取定的常數(+c是因爲怕不停走自環),顯然最後圖形要麼是個環,要麼是個Pho形。
- 若存在的某個約數,考慮在大環上存在小環使得,且,則,由因爲,所以,故若則找到了一個約數,可以遞歸分解下去
考慮倍增枚舉大環,每次在步上找約數,複雜度分析分析是的
代碼
傳送門:bzoj3667
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int tk;
ll n,mxn;
const int p[12]={2,3,5,7,11,13,17,19,23,29};
inline ll rnd(){return ((ll)rand()<<15)+rand();}
inline ll mul(ll x,ll y,ll p)
{
ll d=x*y-(ll)((long double)x/p*y)*p;
return d<0?d+p:d;
}
inline ll gcd(ll x,ll y){return (!y)?x:gcd(y,x%y);}
inline ll fp(ll x,ll y,ll p)
{
ll re=1;
for(;y;y>>=1,x=mul(x,x,p))
if(y&1) re=mul(re,x,p);
return re;
}
inline ll pollar_rho(ll c,ll n)
{
ll g,x=rnd()%n,y=x,k=2;
for(ll i=1;;++i){
x=(mul(x,x,n)+c)%n;
g=gcd(abs(x-y),n);
if(g!=1) return g;
if(i==k) y=x,k<<=1;
}
}
inline bool ck(int p,ll r,ll s,ll n)
{
ll x=fp(p,r,n),y=x,i;
for(i=0;i<s;++i,y=x){
x=mul(x,x,n);
if(x==1)
return (y==1 || y==n-1);
}
return (x==1);
}
inline bool miller_rabin(ll n)
{
if(n<2) return false;
int i;ll r=n-1,s=0;
for(;!(r&1);r>>=1) s++;
for(i=0;i<10;++i){
if(n==p[i]) return true;
if(!ck(p[i],r,s,n)) return false;
}
return true;
}
void fd(ll n)
{
if(n==1 || n<=mxn) return;
if(miller_rabin(n)) {mxn=n;return;}
ll g=pollar_rho(rnd()%n,n);
for(;g==n;g=pollar_rho(rnd()%n,n));
fd(g);fd(n/g);
}
int main(){
for(scanf("%d",&tk);tk;--tk){
scanf("%lld",&n);mxn=0;fd(n);
if(mxn==n) puts("Prime");
else printf("%lld\n",mxn);
}
return 0;
}