1. 程式人生 > >How many prime numbers HDU - 2138 (Miller-Rabin測試)

How many prime numbers HDU - 2138 (Miller-Rabin測試)

傳送門

題意:給出一組數,測試這組數一共有多少個素數

題解:要測試N是否為素數,首先將N-1分解為(2^s)*d。在每次測試開始時,先隨機選一個介於[1,N-1]的整數a,如果對所有的r屬於[0,s-1]都滿足a^dmodN不等於1&&a^((2^r)*d)modN不等於-1,則N是合數,否則,N有3/4的機率為素數。為了提高測試的正確性,可以選擇不同的a進行多次測試。

附上程式碼:



#include<bits/stdc++.h>

using namespace std;

//Miller-Rabin測試
//複雜度O(logn)
typedef long long ll;

ll pow_mod(ll a,ll i,ll n)
{
    if(i==0){
        return 1%n;
    }
    ll temp=pow_mod(a,i>>1,n);
    temp=temp*temp%n;
    if(i&1){
        temp=temp*a%n;
    }
    return temp;
}

bool test(ll n,ll a,ll d)
{
    if(n==2){
        return true;
    }
    if(n==a){
        return true;
    }
    if((n&1)==0){
        return false;
    }
    while(!(d&1)){
        d=d>>1;
    }
    ll t=pow_mod(a,d,n);
    while((d!=n-1)&&(t!=1)&&(t!=n-1)){
        t=(ll)t*t%n;
        d=d<<1;
    }
    return (t==n-1||(d&1)==1);
}

bool isprime(ll n)
{
    if(n<2){
        return false;
    }
    int a[]={2,3,61};
    for(int i=0;i<=2;i++){
        if(!test(n,a[i],n-1)){
            return false;
        }
    }
    return true;
}

int main()
{
    ll n,temp;
    while(scanf("%lld",&n)!=EOF){
        ll res=0;
        for(int i=0;i<n;i++){
            scanf("%lld",&temp);
            if(isprime(temp)){
                res++;
            }
        }
        printf("%lld\n",res);
    }
    return 0;
}