zoukankan      html  css  js  c++  java
  • 算法竞赛模板 素数测试(Miller-Rabin测试)

    基础素数测试模板

    对于大数的素性判断,目前Miller-Rabin算法应用最广泛。一般底数仍然是随机选取,但当待测数不太大时,选择测试底数就有一些技巧了。比如,如果 被测数小于4759123141,那么只需要测试三个底数 a[]={2,7,61} 就足够了。当然,测试的越多,正确的范围也越大。如果你每次都用前7个素数 a[]={2,3,5,7,11,13,17} 进行测试,所有不超过341550071728320的数都是正确的。如果选用 a[]={2,3,7,61,24251} 作为底数,那么10^16内唯一的强伪素数为46856248255981。这样的一些结论使得Miller-Rabin算法在OI中非常实用。通常认为,Miller-Rabin素性测试的正确率可以令人接受,随机选取k个底数进行测试算法的失误率大概为4^(-k)。

    tip:1无法进行判断,只能自行特判为false!

    #include<iostream>
    using namespace std ;
    typedef long long ll;
    ll pow_mod(ll a,ll b,ll r)
    {
        ll ans=1,buff=a;
        while(b)
        {
            if(b&1)
                ans=(ans*buff)%r;
            buff=(buff*buff)%r;
            b>>=1;
        }
        return ans;
    }
    
    bool test(ll n,ll a,ll d)
    {
        if(n==2)return true;
        if(n==a)return false;
        if(!(n&1))return false;
        while(!(d&1))d>>=1;
        ll t=pow_mod(a,d,n);
        while(d!=n-1&&t!=n-1&&t!=1)
        {
            t=t*t%n;
            d<<=1;
        }
        return t==n-1||(d&1)==1;//要么t能变成n-1,要么一开始就t=1
    }
    
    bool isprime(ll n)
    {
        int a[]={2,3,5,7};      //看情况取值
        for(int i=0;i<=3;i++)
        {
            if(n==a[i])return true;
            if(!test(n,a[i],n-1))return false;
        }
        return true;
    }
    int main()
    { 
        int t;
        ll n;  
        for(cin>>t;t;t--)
        {
            cin>>n;
            cout<<((isprime(n))?"Yes":"No")<<endl;
        }
        return 0; 
    }

    ps:注意上述算法中的幂运算是longlong类型,longlong×longlong肯定会出现溢出现象,如果不会java大整数,手里也没有大整数乘法模板的话,有一个小技巧可以避免溢出,方法就是乘法改为加法,把上面的代码:

    ll pow_mod(ll a,ll b,ll r)
    {
        ll ans=1,buff=a;
        while(b)
        {
            if(b&1)
                ans=(ans*buff)%r;
            buff=(buff*buff)%r;
            b>>=1;
        }
        return ans;
    }

    改为:

    ll mod_mul(ll a,ll b,ll n)
    {
        ll res=0;
        while(b)
        {
            if(b&1)
                res=(res+a)%n;
            a=(a+a)%n;
            b>>=1;
        }
        return res;
    }
    
    ll pow_mod(ll a,ll b,ll n)
    {
        ll res=1;
        while(b)
        {
            if(b&1)
                res=mod_mul(res,a,n);
            a=mod_mul(a,a,n);
            b>>=1;
        }
        return res;
    }
  • 相关阅读:
    dlo,学习清单
    OO第一单元优化博客
    BUAA Summer Practice 2017 #1 字符串专场
    OO第一次博客作业
    2018.12.16程设串讲
    助教工作总结 3-22
    软件工程助教3.15总结
    大数据应用技术课程实践--选题与实践方案
    第十五次作业-手写数字识别-小数据集
    第十四次作业-深度学习-卷积
  • 原文地址:https://www.cnblogs.com/kannyi/p/9569506.html
Copyright © 2011-2022 走看看