hoj题双重筛法

题意:
给出一个区间,长度<=1000 000;求其中素数相邻素数之间的差最小的和最大的;
分析:
双重筛法,其中区间的数可能较大,因此如果用试除法的话,显然不行的;
用筛选法,首先第一次筛选出从1到47000之间的素数;第二次筛选时,利用第一次筛
选出来的素数,判断L到U区间范围内的数是否是素数;
因为范围是1<=L< U<=2,147,483,647,而U-L<=1000 000;所以我们可以设置一个1000000
以内的数组,用res[i-L]的值为0或者1来表示是否是素数;
核心算法是第二次的筛选,其中j=begin*prime[i]表示的是在A,B区间中prime[i]的
第一个倍数;依次筛选;
一重筛法的程序如下:
memset(prime,false,sizeof(prime));
tot = 0;
for(int i=2;i<X;i++)
{
if(!prime[i])
isprime[tot++]=i;
for(int j=i+i;j<X;j=j+i)
prime[j] = true;
}

二重筛法的程序如下:
memset(res,false,sizeof(res));
if(m==1)
m=2;
for(int i=0;i<tot&&isprime[i]*isprime[i]<=n;i++)
{
long long temp = (m/isprime[i])+(m%isprime[i]>0);
if(temp==1)
temp = 2;
for(long long j=temp*isprime[i];j<=n;j+=isprime[i])
res[j-m]=true;
}

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
#define X 50000
int tot;
bool prime[50000];
int isprime[10000];
bool res[1000010];
void make_prime()
{
memset(prime,false,sizeof(prime));
tot = 0;
for(int i=2;i<X;i++)
{
if(!prime[i])
isprime[tot++]=i;
for(int j=i+i;j<X;j=j+i)
prime[j] = true;
}
}
int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
make_prime();
long long n,m;
while(cin>>m>>n)
{
memset(res,false,sizeof(res));
int cnt = 0;
if(m==1)
m=2;
for(int i=0;i<tot&&isprime[i]*isprime[i]<=n;i++)
{
long long temp = (m/isprime[i])+(m%isprime[i]>0);
if(temp==1)
temp = 2;
for(long long j=temp*isprime[i];j<=n;j+=isprime[i])
res[j-m]=true;
}
for(int i=0;i<=n-m;i++)
if(!res[i])
cnt++;
cout<<cnt<<endl;
}
return 0;
}

原文地址:https://www.cnblogs.com/yejinru/p/2374685.html