题意:给定一个范围,求此范围内任意两个相邻素数的差值,输出最大值和最小值。
题解: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; }