题意:给你一个区间L,U计算这个区间里面的间距最大的连续素数和最小的连续素数1<=L< U<=2,147,483,647,L,U的间距不超过1000000.
思路:L,U的范围太大了无法使用普通的筛法,将所有素数全部筛完,但是因为它是L,U的一个区间,长度不超过10^6,那可以筛出这个区间的所有素数,然后再求最大最小间距
怎么求L,U区间的素数呢?
我们可以先看1<=L< U<=2,147,483,647这个区间的素数,最大的因子也就是根号2,147,483,647 = 47000,根据筛法的操作,先把2花圈,然后删除2的其他倍数,然后3花圈,删除3的其他倍数,一直删到根号2,147,483,647这个区间就只剩下素数了。
关键是怎么确定开始的L开始的2,3,5....的倍数,这时我们可以用 整数的强制转换 L / prime[i] * prime[i] 这样就正好转换为正好是要删除的prime[i]的倍数,但是还有一点这个开始的数要不小于L,要不去了也没用不在区间里,如果他小于L,继续加prime[i],如果正好整除prime[i]不要删除,素数除以它本身,即它是花圈的那个数,让它从下一个开始,一定记住从花圈的下一个数开始。
#include
#include
#include
#include
using namespace std;
long long p[1000008];
long long pp[1000008];
bool prim[1000008];
bool fp[1000008];
long long Isp()
{
long long k = 0;
prim[0] = prim[1] = 1;
memset(prim,0,sizeof(prim));
for(long long i = 2; i <= 47000; i++)
{
if(!prim[i])
{
p[k++] = i;
for(long long j = i*i; j <= 47000; j += i)
{
prim[j] = 1;
}
}
}
return k;
}
void fun(long long L,long long U,long long cnt)
{
long long i,j,b,k = 0;
memset(fp,1,sizeof(fp));
for(i = 0; i < cnt; i++)
{
b = L / p[i];
while(b*p[i] < L || b <= 1)
b++;
for(j = b*p[i]; j <= U; j+=p[i])
{
fp[j-L] = 0;
}
if(L == 1)
fp[0] = 0;
}
}
int main()
{
long long U,L;
long long cnt = Isp();
while(scanf("%I64d%I64d",&L,&U) != EOF)
{
long long sum = 0;
fun(L,U,cnt);
int Max = -999999,Min = 9999999;
long long flagMax = 0,flagMin = 0;
for(long long i = 0; i <= U-L; i++)
{
if(fp[i])
{
pp[sum++] = L+i;
}
}
if(!sum || sum == 1)
{
printf("There are no adjacent primes.\n");continue;
}
for(int i = 0; i < sum-1; i++)
{
if(pp[i+1] - pp[i] > Max)
{
Max = pp[i+1] - pp[i];flagMax = i;
}
if(pp[i+1] - pp[i] < Min)
{
Min = pp[i+1] - pp[i];flagMin = i;
}
}
printf("%I64d,%I64d are closest, %I64d,%I64d are most distant.\n",pp[flagMin],pp[flagMin+1],pp[flagMax],pp[flagMax+1]);
}
return 0;
}