• 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
    */
  • 相关阅读:
    web 框架本质 及python三大框架对比
    jquery 进阶 bootstrap
    BOM DOM jQuery
    JS基础
    Linux(8)- nginx+uWSGI+virtualenv+supervisor 发布web服务器
    Linux(7)- Nginx.conf主配置文件、Nginx虚拟主机/访问日志/限制访问IP/错误页面优化、Nginx反向代理、Nginx负载均衡
    Linux(6)- redis发布订阅/持久化/主从复制/redis-sentinel/redis-cluster、nginx入门
    Linux(5)- MariaDB、mysql主从复制、初识redis
    Linux(4)- centos7安装python3、Linux下安装、配置virtualenv、确保开发环境的一致性、虚拟环境之virtualenvwrapper、vim
    Linux(3)- 用户管理、文件与目录权限、常用命令、Linux软件包管理
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9697260.html
Copyright © 2020-2023  润新知