若n为素数,取a<n,设n-1=d*2^r,则要么a^d≡1(mod n),要么∃0≤i<r,s.t.(s.t.是满足或使得的意思)a^(d*2^i)≡-1(mod n).

思路:找k个数,全部进行上述两个测试(至少满足一个),若都能通过测试,则可以认为n是素数。

//该方法存在一定的问题,当然,出错的概率很小。

k个数选取:一般选取8个素数(zhx选的{2,3,5,7,11,13,17,37},他说这八个数判定long long以内的素数不会出错)

实测:找出区间[x,y]中的素数个数

   数据范围:1<=x<=y<=2147483647,y-x<=10^6

可以过

#include<iostream>
#include<cstdio>

using namespace std;

int prime[8]={2,3,5,7,11,13,17,37};

int ksm(int m,int n,int p){
    if(p==1)return 0;
    int ans=1;
    while(n){
        if(n&1)ans=1ll*ans*m%p;
        m=1ll*m*m%p;
        n>>=1;
    }
    return ans;
}


bool miller_rabin(int n,int a)
{
    int d=n-1,r=0;//跟上述内容中的字母一致
    while(d%2==0)
        d=d>>1,r++;
    int z=ksm(a,d,n);//快速幂求a^d%n的值
    if(z==1)
        return true;
    for(int i=0;i<r;i++)
    {
        if(z==n-1)
            return true;
        z=1ll*z*z%n;
    }
    return false;
}

bool check(int n)
{
    if(n<2)
        return false;
    for(int a=0;a<8;a++)//判断n是不是素数
    {
        if(n==prime[a])//如果该数是素数表中的(prime)里的,直接返回true 
            return true;
        if(n%prime[a]==0)//如果prime里有因子,直接返回false 
            return false;
        if(!miller_rabin(n,prime[a]))
            return false;//如果素性测试返回的是false,则证明n不是素数 
    }
    return true;//如果能走到这一步,就说明n是素数。 
}

int x,y;
long long ans;

int main()
{
    scanf("%d%d",&x,&y);
    for(int i=x;i<=y;i++)
    {
        if(check(i))
            ans++;
    }
    printf("%lld",ans);
    return 0;
}

 

posted on 2020-03-23 21:34  Allen_lml  阅读(287)  评论(0编辑  收藏  举报