nefu120-梅森素数(Lucas-Lehmer判定法和Miller测试法)


准备知识:

梅森素数:它是发现已知最大素数的有效途径。如果m是一个正整数,且是一个素数,则2^m-1必是素数。反之,如果m是一个正整数、素数,且2^m-1称作第m梅森数;如果p是一个素数,并且也是素数,那么就称为梅森素数。而梅森数可能是素数,也可能是合数。

(由于很多word公式无法导入,只能以截图方式展现。)


Lucas-Lehmer判定法

#include <iostream>

using namespace std;

#define ll long long

ll multi(ll a,ll b,ll mod)
{
    ll ans=0;
    while(b>0)
    {
        if(b&1)
        {
            ans=(ans+a)%mod;
        }
        b>>=1;
        a=(a<<1)%mod;
    }
    return ans;
}



int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int p;
        ll r1 = 4,r2=0,mp=1;
        cin>>p;
        mp = (mp<<p) -1;
        int i;
        for(i=0;i<p-2;i++)
        {
            r2 = multi(r1,r1,mp);
            r2 = (r2 - 2)%mp;
            r1 = r2;
        }

        if(r2==0||p==2)
            cout<<"yes"<<endl;
        else
            cout<<"no"<<endl;
    }
    return 0;
}

Miller测试法

这里用快速幂时,我们需要注意的是,如果直接a*a%n是有可能有溢出风险的,因为都是long long 类型的。所以这里还需要加入一个基于加法的快速乘法取模法,来求a*a%n。

#include <iostream>
#include <time.h>
#include <cstdio>
#include <cstdlib>

#define ll long long
#define Times 12

using namespace std;

ll random(ll n)
{
    return (ll)((double)rand()/RAND_MAX*n+0.5);
}

ll multi(ll a,ll b,ll m)
{
    ll ans = 0;
    while(b>0)
    {
        if(b&1)
        {
            ans=(ans+a)%m;
        }
        b>>=1;
        a=(a<<1)%m;
    }
    return ans;
}

ll quick_mod(ll a,ll b,ll m)
{
    ll ans = 1;
    while(b)
    {
        if(b&1)
        {
            ans = multi(ans,a,m);
            //ans=ans*a%m;
        }
        b>>=1;
        a = multi(a,a,m);
        //a=a*a%m;
    }
    return ans;
}

bool Witness(ll a,ll n)
{
    ll m = n-1;
    int j=0;
    while(!(m&1))
    {
        j++;
        m>>=1;
    }
    ll x = quick_mod(a,m,n);    //a^(n-1)%n
    if(x==1 || x==n-1)
        return false;
    while(j--)
    {
        x = x*x%n;
        if(x == n-1)
            return false;
    }
    return true;
}

bool miller_rabin(ll n)
{
    if(n<2) return false;
    if(n==2) return true;
    if( !(n&1) ) return false;
    for(int i=1;i<=Times;i++)
    {
        ll a = random(n-2)+1;
        if(Witness(a,n)) return false;
    }
    return true;
}


int main()
{
    int p,T;
    cin>>T;
    while(T--)
    {
        cin>>p;
        ll n;
        n=(ll)1<<p;
        n=n-1;
        if(miller_rabin(n))
            cout<<"yes"<<endl;
        else
            cout<<"no"<<endl;
    }

    return 0;


}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值