题意:给定一个范围,求此范围内任意两个相邻素数的差值,输出最大值和最小值。
题解:1 <= L <= U <= 2^31,U-L >= 1000000 在空间限制的条件下,可以先将[ L, U ] 平移到 [ 0, U-L+1 ]。然后用筛选法做。
注意:筛选的时候由于1不是任何素数的倍数,所以需要特殊处理。
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAX = 1000009;
const int MAX2 = 50000;
int p[MAX2], a[MAX2], pn;
bool f[MAX];
void prime ()
{
int i, j; pn = 0;
memset(a,0,sizeof(a));
for ( i = 2; i < MAX2; i++ )
{
if ( !a[i] ) p[pn++] = i;
for ( j = 0; j < pn && i * p[j] < MAX2 && (p[j] <= a[i] || a[i] == 0); j++ )
a[i*p[j]] = p[j];
}
}
void sift ( int L, int U )
{
int l, r, i, j;
int s = (int)sqrt(U+0.0);
memset(f,0,sizeof(f));
if ( L == 1 ) f[0] = 1; //从1的需要特殊处理,因为1筛不掉
for ( i = 0; i < pn && p[i] <= s; i++ )
{
l = L / p[i];
r = U / p[i];
if ( l <= 1 ) l = 2;//素数本身不能被筛掉
for ( j = l; j <= r; j++ )
{
if (j * p[i] >= L && j * p[i] <= U)
f[j*p[i]-L] = 1;
}
}
}
void count ( int L, int U, int& pnum, int& c1, int& c2, int& d1, int& d2 )
{
sift(L,U);
pnum = 0;
int l, r, t = U - L + 1;
int mmin = MAX, mmax = -1;
for ( int i = 0; i < t; i++ )
{
if ( !f[i] )
{
pnum++;
if ( pnum == 1 )
l = r = i;
if ( pnum >= 2 )
{
l = r, r = i;
if ( mmin > r-l+1 )
{
mmin = r - l + 1;
c1 = l, c2 = r;
}
if ( mmax < r-l+1 )
{
mmax = r - l + 1;
d1 = l, d2 = r;
}
}
}
}
c1 += L, c2 += L, d1 += L, d2 += L;
}
int main()
{
prime();
int L, U;
int c1, c2, d1, d2, pnum;
while ( scanf("%d%d",&L,&U) != EOF )
{
count(L,U,pnum,c1,c2,d1,d2);
if ( pnum >= 2 )
printf("%d,%d are closest, %d,%d are most distant.\n",c1,c2,d1,d2);
else
printf("There are no adjacent primes.\n");
}
return 0;
}