• 【数学】【筛素数】Miller-Rabin素性测试 学习笔记


        Miller-Rabin是一种高效的随机算法,用来检测一个数$p$是否是素数,最坏时间复杂度为$log^3 p$,正确率约为$1-4^{-k}$,$k$是检验次数。

    一、来源

        Miller-Rabin是由Miller和Rabin两个人根据费马小定理的逆定理,也就是费马测试优化过来的。费马小定理就是$$a^{p-1}equiv 1(mod p)$$

        我们知道当$p$为素数时费马小定理才成立,但是如果一个数满足费马小定理,它一定是素数吗?可以发现,当这个数肥肠小时,它是满足的,但是有一天人们发现341这个数满足以2为底的费马小定理,满足$2^{340}equiv 1(mod 341)$,但是它是合数$(341=11 imes 31)$。

        这时,Miller和Rabin就改进了这个叫费马测试的东西……

        我不会证谁来证一下

    二、二次探测定理

        有一个叫二次探测定理的东西,可以有效地提升费马小定理的正确性。如果对于素数$p$,有正整数$x<p$且$x^2equiv 1(mod p)$;可以推得$x^2-1equiv 0(mod p)Rightarrow p|x^2-1Rightarrow p|(x-1)(x+1)$,而$x<p$,所以如果$p|(x-1)$的话,$x-1=0,x=1$,或$p|x+1$,则$x=p-1$。因此,就有了Miller-Rabin测试。

    三、Miller-Rabin素性测试

        有了二次探测定理,我们试着进行341的以2为底的费马测试。$2^{340}equiv 1(mod 341)$,如果341是素数,那么也满足二次探测定理,也就是$2^{170}equiv 1(mod 341)$。而170还是个偶数,可以继续进行二次探测定理。这时它就凉了,因为$2^{85}equiv 32(mod 341)$,而它没有通过二次探测定理,所以341不是个素数。

        同时,因为费马小定理没有要求底为什么,所以只以2为底肯定会放过一些漏网之鱼,我们应该多选一些数为底,这样才能使判断的正确性提高。不过这个底最好选择素数(不知道为什么,可能与答案的模数大都为质数一样吧...),来保证正确性。同时,在学习这个算法时,网上会有一写神奇的结论,比如选3个特定的底$2,7,61$,就可以通过小于$4,759,123,141$的所有素数的测试,而选$latex 2,3$为底,可以通过$1,373,653$以内的测试。因此很多人都喜欢随机几个数作为底,而题目给出的质数也不一样,这就是靠碰运气了。不过上面分析过,它的错误率只有约$4^{-k}$,所以出题人在不知道你的底数的情况下,正确率是特别高的。

    四、总结

        Miller-Rabin是肥肠高效的,写起来也比较方便。而题目中远没有变态到让你线筛出$10^7$个数来,有很多包括空间在内的资源都浪费了,尤其是在卡空间的题中。这时候Milller-Rabin就是一个不错的选择。

    五、Code(luogu 线性筛模板)

        因为这里的范围是$10^7$,所以用上面的特定底数$2,7,61$是可以通过的

    #include<cstdio>
    #include<cstring>
    long long qpow(long long x,long long y,long long p)//快速幂及模数
    {
        long long ans=1,m=x;
        while(y)
        {
            if(y&1)
                ans*=m;
            ans%=p;
            m*=m;
            m%=p;
            y>>=1;
        }
        return ans;
    }
    bool check(long long x,long long y,long long p)//二次探测
    {
        long long tmp=qpow(x,y,p);
        if(tmp!=1&&tmp!=p-1)
            return false;
        if(tmp==p-1)
            return true;
        if(tmp==1&&(y&1))
            return true;
        return check(x,y>>1,p);
    }
    bool millerrabin(long long x)
    {
        if(x<=1)
            return false;
        if(x==2||x==7||x==61||(check(2,x-1,x)&&check(7,x-1,x)&&check(61,x-1,x)))//注意判断到自己会挂掉,我们已经知道他们是素数了就不管了qwq
            return true;
        return false;
    }
    int main()
    {
        int n,m;
        long long u;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i)
        {
            scanf("%lld",&u);
            if(millerrabin(u))
                puts("Yes");
            else
                puts("No");
        }
        return 0;
    }
    

      

  • 相关阅读:
    第二阶段站立会议(3)
    第二阶段站立会议(2)
    第二阶段站立会议(1)
    返回一个最大联通子数组的和
    场景调研
    课程改进意见
    百度搜索引擎——评价
    求1的个数
    《校园封神榜》个人工作总结——第十天
    《校园封神榜》个人工作总结——第九天
  • 原文地址:https://www.cnblogs.com/wjyyy/p/note1.html
Copyright © 2020-2023  润新知