【模板】Miller-Rabin & Pollar-Pho


Miller-Rabin

判斷大素數的方法。

對於素數p,僅存在x=1,p1x=1,p-1,使得x21(modp)x^2\equiv 1\pmod p

任取前幾小的素數(通常前10小的素數)qq,進行二次探測:

  • 首先滿足歐拉定理qp11(modp)q^{p-1}\equiv 1\pmod p
  • 求出t,st,s滿足p1=2stp-1=2^st,且tt爲奇數
  • qtq^t逐步平方若q2t1(modp)q^{2t}\equiv 1\pmod pqtq^t不是1,p11,p-1,則pp非奇數

通過二次探測的數很大概率上爲素數。

Pollar-Pho

快速分解nn的所有質因子的方法:

每次找出一個nn的一個約數:

  • 任取x[0,n)x\in [0,n),設變化爲f(x)=(x2+c)%n,cf(x)=(x^2+c)\% n,c[0,n)[0,n)中任意取定的常數(+c是因爲怕x2x^2不停走自環),顯然最後圖形要麼是個環,要麼是個Pho形。
  • 若存在nn的某個約數a(a>1)a(a>1),考慮在大環上存在小環使得xixj(modn),i<jx_i\neq x_j \pmod n,i<j,且xixj(moda)x_i\equiv x_j\pmod a,則a(xixj)a|(|x_i-x_j|),由因爲ana|n,所以agcd(n,xixj)a|\gcd(n,|x_i-x_j|),故若gcd(n,xixj)>1\gcd(n,|x_i-x_j|)>1則找到了一個約數,可以遞歸分解下去

考慮倍增枚舉大環,每次在2k2^k步上找約數,複雜度分析分析是O(4nlogn)O(^4\sqrt n\log n)


代碼

傳送門: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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章