【模板】Miller-Rabin & Pollar-Pho

本文介绍了两种算法:Miller-Rabin用于高效检测大素数,通过欧拉定理和二次探测来判断;Pollar-Pho算法用于快速分解大整数的质因子,通过图形变化找到小环来确定约数。并提供了相关代码实现。
摘要由CSDN通过智能技术生成

Miller-Rabin

判断大素数的方法。

对于素数p,仅存在 x = 1 , p − 1 x=1,p-1 x=1,p1,使得 x 2 ≡ 1 ( m o d p ) x^2\equiv 1\pmod p x21(modp)

任取前几小的素数(通常前10小的素数) q q q,进行二次探测:

  • 首先满足欧拉定理 q p − 1 ≡ 1 ( m o d p ) q^{p-1}\equiv 1\pmod p qp11(modp)
  • 求出 t , s t,s t,s满足 p − 1 = 2 s t p-1=2^st p1=2st,且 t t t为奇数
  • q t q^t qt逐步平方若 q 2 t ≡ 1 ( m o d p ) q^{2t}\equiv 1\pmod p q2t1(modp) q t q^t qt不是 1 , p − 1 1,p-1 1,p1,则 p p p非奇数

通过二次探测的数很大概率上为素数。

Pollar-Pho

快速分解 n n n的所有质因子的方法:

每次找出一个 n n n的一个约数:

  • 任取 x ∈ [ 0 , n ) x\in [0,n) x[0,n),设变化为 f ( x ) = ( x 2 + c ) % n , c f(x)=(x^2+c)\% n,c f(x)=(x2+c)%n,c [ 0 , n ) [0,n) [0,n)中任意取定的常数(+c是因为怕 x 2 x^2 x2不停走自环),显然最后图形要么是个环,要么是个Pho形。
  • 若存在 n n n的某个约数 a ( a &gt; 1 ) a(a&gt;1) a(a>1),考虑在大环上存在小环使得 x i ≠ x j ( m o d n ) , i &lt; j x_i\neq x_j \pmod n,i&lt;j xi̸=xj(modn),i<j,且 x i ≡ x j ( m o d a ) x_i\equiv x_j\pmod a xixj(moda),则 a ∣ ( ∣ x i − x j ∣ ) a|(|x_i-x_j|) a(xixj),由因为 a ∣ n a|n an,所以 a ∣ gcd ⁡ ( n , ∣ x i − x j ∣ ) a|\gcd(n,|x_i-x_j|) agcd(n,xixj),故若 gcd ⁡ ( n , ∣ x i − x j ∣ ) &gt; 1 \gcd(n,|x_i-x_j|)&gt;1 gcd(n,xixj)>1则找到了一个约数,可以递归分解下去

考虑倍增枚举大环,每次在 2 k 2^k 2k步上找约数,复杂度分析分析是 O ( 4 n log ⁡ n ) O(^4\sqrt n\log n) O(4n logn)


代码

传送门: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值