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;
    }
  • 相关阅读:
    BZOJ 2034 【2009国家集训队】 最大收益
    vijos P1780 【NOIP2012】 开车旅行
    BZOJ 2115 【WC2011】 Xor
    BZOJ 3631 【JLOI2014】 松鼠的新家
    BZOJ 4717 改装
    BZOJ 2957 楼房重建
    BZOJ 4034 【HAOI2015】 T2
    BZOJ 1834 【ZJOI2010】 network 网络扩容
    BZOJ 2440 【中山市选2011】 完全平方数
    BZOJ 2733 【HNOI2012】 永无乡
  • 原文地址:https://www.cnblogs.com/kannyi/p/9569506.html
Copyright © 2011-2022 走看看