Miller-Rabin
判断大素数的方法。
对于素数p,仅存在 x = 1 , p − 1 x=1,p-1 x=1,p−1,使得 x 2 ≡ 1 ( m o d p ) x^2\equiv 1\pmod p x2≡1(modp)。
任取前几小的素数(通常前10小的素数) q q q,进行二次探测:
- 首先满足欧拉定理 q p − 1 ≡ 1 ( m o d p ) q^{p-1}\equiv 1\pmod p qp−1≡1(modp)
- 求出 t , s t,s t,s满足 p − 1 = 2 s t p-1=2^st p−1=2st,且 t t t为奇数
- 由 q t q^t qt逐步平方若 q 2 t ≡ 1 ( m o d p ) q^{2t}\equiv 1\pmod p q2t≡1(modp)且 q t q^t qt不是 1 , p − 1 1,p-1 1,p−1,则 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 > 1 ) a(a>1) a(a>1),考虑在大环上存在小环使得 x i ≠ x j ( m o d n ) , i < j x_i\neq x_j \pmod n,i<j xi̸=xj(modn),i<j,且 x i ≡ x j ( m o d a ) x_i\equiv x_j\pmod a xi≡xj(moda),则 a ∣ ( ∣ x i − x j ∣ ) a|(|x_i-x_j|) a∣(∣xi−xj∣),由因为 a ∣ n a|n a∣n,所以 a ∣ gcd ( n , ∣ x i − x j ∣ ) a|\gcd(n,|x_i-x_j|) a∣gcd(n,∣xi−xj∣),故若 gcd ( n , ∣ x i − x j ∣ ) > 1 \gcd(n,|x_i-x_j|)>1 gcd(n,∣xi−xj∣)>1则找到了一个约数,可以递归分解下去
考虑倍增枚举大环,每次在 2 k 2^k 2k步上找约数,复杂度分析分析是 O ( 4 n log n ) O(^4\sqrt n\log n) O(4nlogn)的
代码
传送门: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;
}