Miller-Rabin与二次探测

素数在数论中经常被用到。也是数论的基础之一。

人们一直在讨论的问题是,怎样快速找到素数?或者判断一个数是素数?

1.根号n枚举

原始暴力方法。

2.埃氏筛

每个合数会被筛质因子次数次。复杂度O(NloglogN)

3.线性筛素数

每个合数只会被它的最小质因子筛一次。

线性筛还可以筛各种函数

具体见:SIEVE 线性筛

4.Miller_Rabin

利用:二次探测,费马小定理。

二测探测:

若P是质数,那么若x^2=1 mod P,则,x=1或者P-1

证明:即x^2-1 = 0 mod P,P|(x-1)*(x+1)

由于P是质数,所以一定是在(x-1)或者(x+1)里面存在P的质因子。

所以,有P|(x-1)或者P|(x+1),所以,x=1,或者,x=-1=P-1

如果有x^2=1 mod P,但是不满足x=1或者x=P-1,那么这个P一定不是素数。

 

费马小定理:

对于质数P,任意整数a(a!=P) 都有,a^(P-1)=1 mod P

这个也可以作为质数的判定条件。存在一个a不满足P一定也不是质数,。

 

把这两个结合起来,就可以进行Miller_Robin算法了。

 

具体地:

1.传入一个数n,lp=n-1

再传入一个随机数a,但是一般是质数,如2,3,5,7,61,等等

2.把lp中的所有质因子2都提出来,提出来之后的数设为d,s记录2的次数。

3.令$t=a^d mod n$,如果t==1或者t==n-1那么返回true

因为,再把s都乘回去的时候,一定会得到$a^{n-1}=1 mod n$

其实s为0,也可以直接返回false,因为n一定就是一个偶数了。

4.然后不断把s往回乘,其实是平方,因为d在指数的位置。

记录平方之前的数las,之后,如果t==1而las!=1并且las!=n-1那么就返回false

(根据二次探测)

5.s乘完后,如果n是质数,那么t=1,(根据费马小定理)。否则返回false

6.是true的话,返回1多试几次。

7.输出结果。

 据说试1次,误判概率为1/4,那么试4次误判的概率就是1/(4^4)很小了。

 

模板:

luoguP3383(用Miller_Rabin过线性筛)

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100000+5;
int a[3]={2,7,61};
ll qm(ll x,ll y,ll mod){
    ll ret=1;
    while(y){
        if(y&1) (ret*=x)%=mod;
        (x*=x)%=mod;
        y>>=1;
    }
    return ret;
}
bool che(ll a,ll x){
    int s=0;
    ll t;
    ll lp=x-1;
    while(!(lp&1)){
        s++;
        lp>>=1;
    }
    t=qm(a,lp,x);
    if(t==1||t==x-1) return true;
    if(s==0) return false;
    ll las=t;
    for(int i=0;i<s;i++){
        las=t;
        (t*=t)%=x;
        if(t==1&&(las!=1&&las!=x-1)) return 0;    
    }
    if(t!=1) return 0;
    return 1;
}
int n,m;
bool M_R(ll n){
    if(n==2||n==7||n==61) return true;
    if(n<2||n%2==0||n%7==0||n%61==0) return false;
    for(int i=0;i<3;i++){
        ll b=a[i];
        if(b!=n){
            if(!che(b,n)) return false;
        }
    }
    return true;
}
int main(){
    scanf("%d%d",&n,&m);
    ll x;
    for(int i=1;i<=m;i++){
        scanf("%lld",&x);
        if(x==2||x==3||x==5||x==7||x==11||x==13){
            puts("Yes");continue;
        }
        if(x%2==0||x%3==0||x%5==0||x%7==0||x%11==0||x%13==0){
            puts("No");continue;
        }
        if(M_R(x)) puts("Yes");
        else puts("No");
    }
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/9/24 20:50:22
*/

 

posted @ 2018-09-24 23:14  *Miracle*  阅读(1746)  评论(0编辑  收藏  举报