poj 3641 Pseudoprime numbers(Miller-Rabin素数测试)

本文介绍了使用Miller-Rabin素数测试判断大整数n(如10^14或更大)是否为素数的方法,并提供了详细的算法实现,包括如何避免卡迈尔数导致的误判。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://poj.org/problem?id=3641

题目大意:根据已a为基的伪素数的定义,判断p是否是已a为基的伪素数。(p为合数且满足a^p mod p = a), p<10^9

解题思路:p<10^9,用普通素数判定即可通过,去模运算用快速幂实现。

参考代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
ll p,a;
bool isprime(ll n)
{
   for(int i=2;i*i<=n;i++)
        if(n%i==0) return  false;
   return true;
}
ll quickpow_mod(ll a,ll b,ll mod)
{
    ll ans=1;
    while(b){
        if(b&1) ans=(ans*a)%mod;
        b>>=1;
        a=(a*a)%mod;
    }
    return  ans;
}
int main()
{
 //  freopen("input.txt","r",stdin);
   while(cin>>p>>a&&p+a){
     if(!isprime(p)&&quickpow_mod(a,p,p)==a) cout<<"yes";
    else cout<<"no";
    cout<


上面这道题似乎与题目Miller-Rabin素数测试没有关系哈,下面就给个代码应用Miller-Rabin素数测试判断大的整数n(10^14或者更大)是否为素数.


#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
const int N = 10;                //换底的次数,次数越多,n为素数的概率越大
ll n;                            //n=10^14,普通测素数的方法不到70组数据就会超时,何况n可能会更大(Java?)
ll random(ll n)
{
    return (ll)((double)rand()/RAND_MAX*n+0.5);
}
ll multi(ll a,ll b,ll mod)
{
    ll ans=0;
    while(b){
        if(b&1) ans=(ans+a)%mod;
        b>>=1;
        a=(a+a)%mod;
    }
    return ans;
}
ll quickpow_mod(ll a,ll b,ll mod) //long long 10^19 数据很大时乘法a*a也会溢出,也应二分写乘法取模
{
    ll ans=1;
    while(b){
        if(b&1) ans=multi(ans,a,mod);
        b>>=1;
        a=multi(a,a,mod);
    }
    return ans;
}
bool Miller_rabin(ll n)
{
    for(int i=0;i < N; i++){
        ll a =random(n-2) + 1;
        if(quickpow_mod(a,n-1,n)!=1) return false;
    }
    return true;
}
int main()
{
 //  freopen("input.txt","r",stdin);
   cout<>n){
    if(Miller_rabin(n)) cout<<"Yes"<

 

改进Miller-Rabin素数测试

    似乎Miller-Rabin素数测试已无瑕疵,然而有一类卡迈尔数,将导致Miller-Rabin素数测试出现错误。

定义:  一个合数n,若对于所有满足(b,n)=1的正整数b都有b^n-1=1(mod n) 成立,则成n为卡迈尔数。

    那么如何改进上述算法,以排除卡迈尔数呢?首先介绍二次探测定理。

二次探测定理: 如果p是一个素数,且0<x<p,则方程x^2%p=1的解为x=1或x=p-1.

    那么可以根据二次探测定理,再利用费马小定理计算b^n-1%的过程中增加对整数n的二次探测,一旦发现违背二次探测条件,即得出n不是素数的结论。

算法实现:(增加一个witness(),改写一下Miller_rabin())

 

bool Witness(ll a,ll n)
{
    ll m=n-1;
    int j=0;
    while(!(m&1)){
        j++;
        m>>=1;
    }
    ll x=quickpow_mod(a,m,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;
    else if(n == 2) return true;
    else if(!(n&1)) return false;
    for(int i=0;i < N; i++){
        ll a =random(n-2) + 1;
        if( Witness ( a , n ) ) return false;
    }
    return true;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值