Miller-Rabin与Pollard-Rho备忘

Miller-Rabin素性测试算法:

  根据费马小定理当p为素数时成立,所以如果存在一个a使x不满足此定理,则x必然不为素数。

  但这是充分条件而不是必要条件,所以对于每个a,可能存在满足定理的x,这时就要选取多个a同时检测,这种验证素性的方法即为Miller-Rabin算法。

  当a取2,3,5,7时,可以直接检测1e13内的所有整数。

  但是存在非素数通过检测,这时需要进行二次检测。

  可以证明当p为奇素数时,$x^2\equiv 1(mod\ p)$的解有且仅有两个:1和p-1。根据这个定理可以再次检测出一些非素数。

  但是仍然存在一些数无法辨别,这些数被称为“强伪素数”,多选取一些数为底数检测即可(一般在[1,p)内选3个左右做二次检测就可以保证一定的正确率了)。

  概括一下算法的具体流程:

  1.先特判掉1,2和2的倍数。

  2.选取3个以上[1,p)的数a。

  3.对每个a先将p-1中2的因子去除,再逐个加上并实时检测是否出现不合法情况。

  4.同时要注意判定$a^{p-1}\equiv 1(mod\ p)$

 

Pollard-Rho质因数分解算法:

  一种复杂度证明较为复杂的算法,主要思想是先求出n的一个因子p,然后对于p和n/p分别递归下去,如果发现p为素数则停止递归。(这里判断素数需要用到Miller-Rabin)。

  主要思想是,让a和b同时在$f(x)=x^2+c$的轨迹上走(c需要变化),每2的次幂步进行一次a=b。每次判定若gcd(|a-b|,n)在(1,n)中则返回,当a==b时退出。

  这样的算法,如果将a和b直到a=b的轨迹画出来,会是一条链加一个环,a每次在上面走1步,b走两步,形如$\rho$。

 1 #include<cstdio>
 2 #include<vector>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 vector<ll>ls;
 9 const int A[]={0,2,3,5,7,61,24251,131};
10 ll T,e,n,c,d,y,p,r,w,mx;
11 ll Rand(ll l,ll r){ return (((ll)rand()<<31)+rand())%(r-l+1)+l; }
12 ll gcd(ll a,ll b){ return (b) ? gcd(b,a%b) : a; }
13 
14 ll ksc(ll a,ll b,ll p)
15 {
16     ll t=a*b-(ll)((long double)a*b/p+0.5)*p;
17     return (t<0)?t+p:t; 
18 }
19 
20 ll ksm(ll a,ll b,ll mod){
21     ll res=1;
22     for (; b; a=ksc(a,a,mod),b>>=1)
23         if (b & 1) res=ksc(res,a,mod);
24     return res;
25 }
26 
27 ll find(ll n,int c){
28     ll i=1,k=2,x=Rand(0,n-1),y=x,d;
29     while (1){
30         i++; x=(ksc(x,x,n)+c)%n; d=gcd(abs(y-x),n);
31         if (d>1 && d<n) return d;
32         if (y==x) return -1;
33         if (i==k) y=x,k<<=1;
34     }
35 }
36 
37 ll Rho(ll n,int c){ ll p=-1; while (p==-1) p=find(n,c--); return p; }
38 
39 bool chk(ll a,ll n){
40     ll m=n-1,x,y; int k=0;
41     while (!(m&1)) m>>=1,k++;
42     x=ksm(a,m,n);
43     rep(i,1,k){
44         y=ksm(x,2,n);
45         if (y==1 && x!=1 && x!=n-1) return 1;
46         x=y;
47     }
48     return y!=1;
49 }
50 
51 bool Miller(ll n){
52     if (n==2) return 1;
53     if (!(n&1)) return 0;
54     rep(i,1,3) if (chk(Rand(1,n-1),n)) return 0;
55     return 1;
56 }
57 
58 void Fac(ll x,int c){
59     if (x==1) return;
60     if (Miller(x)) { ls.push_back(x); return; }
61     ll p=Rho(x,c); Fac(p,c);
62     while (x%p==0) x/=p;
63     Fac(x,c);
64 }
65 
66 int main(){
67     for (scanf("%lld",&T); T--; ){
68         scanf("%lld",&n); ls.clear();
69         if (Miller(n)) { puts("Prime"); continue; }
70         Fac(n,19260817); mx=0;
71         for (vector<ll>::iterator it=ls.begin(); it!=ls.end(); it++) mx=max(mx,*it);
72         printf("%lld\n",mx);
73     }
74     return 0;
75 }

 

posted @ 2018-07-03 10:54  HocRiser  阅读(258)  评论(0编辑  收藏  举报