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

题目链接: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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值