题目:POJ2689.
题目大意:给定区间
[
L
,
R
]
[L,R]
[L,R],要求区间中差最小的相邻素数和差最大的相邻素数.
1
≤
L
<
R
≤
2
31
−
1
,
1
≤
R
−
L
+
1
≤
1
0
6
1\leq L<R\leq 2^{31}-1,1\leq R-L+1\leq 10^6
1≤L<R≤231−1,1≤R−L+1≤106.
这道题一看不可做,毕竟 L , R < 2 31 L,R< 2^{31} L,R<231的数据范围太大,但是一看 R − L ≤ 1 0 6 R-L\leq 10^6 R−L≤106的限制就会想到一定是从区间 [ L , R ] [L,R] [L,R]中的数入手.
想到尝试枚举区间 [ L , R ] [L,R] [L,R]中的每一个数,暴力计算每一个数是否为合数,然后统计,发现这样做时间复杂度是 O ( ( R − L ) R ) O((R-L)\sqrt R) O((R−L)R)的,过不了.
考虑一个数为合数时因数的性质,发现一个合数 n n n必定有一个因数 x x x满足 x ≤ n x\leq \sqrt n x≤n,所以考虑利用这个性质来做这道题.
利用上面那个性质可以想到,区间 [ L , R ] [L,R] [L,R]中的任意一个合数必定有一个因数 x x x满足 x ≤ R x\leq \sqrt R x≤R,所以可以枚举 [ 2 , R ] [2,\sqrt R] [2,R]内的所有数,把这些数在区间 [ L , R ] [L,R] [L,R]内的倍数全部打上合数的标记,最后把没打标记的数取出来统计即可.时间复杂度 O ( ( R − L ) log R ) O((R-L)\log\sqrt R) O((R−L)logR),但是我用这个做法TLE了…
考虑优化,每次把 [ 2 , R ] [2,\sqrt R] [2,R]内的质数筛出来,直接用质数去筛 [ L , R ] [L,R] [L,R]内的数即可.按照 [ 1 , n ] [1,n] [1,n]中的素数有 O ( n log n ) O(\frac{n}{\log n}) O(lognn)来计算的话,这个算法的时间复杂度约为 O ( R + ( R − L ) log log R ) O(\sqrt R+(R-L)\log\log\sqrt{R}) O(R+(R−L)loglogR).
代码如下:
#include<cstdio>
#include<iostream>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1000000;
int pr[N+9],tpr,b[N+9];
int l,r;
int cnt[N+9],p[N+9],tp;
int mx,mn;
Abigail sieve(int n){
for (int i=2;i<=n;++i) b[i]=1;
for (int i=2;i<=n;++i){
if (b[i]) pr[++tpr]=i;
for (int j=1;j<=tpr&&i*pr[j]<=n;++j){
b[i*pr[j]]=0;
if (i%pr[j]==0) break;
}
}
}
Abigail work(){
int ll,rr,now=0;
for (now=1;now<=tpr&&pr[now]*pr[now]<=r;++now);
--now;
for (int i=1;i<=tpr;++i){
ll=l/pr[i];
if (pr[i]*ll<l) ++ll;
if (ll<2) ll=2; //避免自己把自己筛掉
rr=r/pr[i];
for (int j=ll;j<=rr;++j)
cnt[pr[i]*j-l+1]=1;
}
for (int i=0;i<=r-l;++i)
if (!cnt[i+1]&&l+i>1) p[++tp]=l+i;
mx=mn=1;
for (int i=2;i<tp;++i){
if (p[mx+1]-p[mx]<p[i+1]-p[i]) mx=i;
if (p[mn+1]-p[mn]>p[i+1]-p[i]) mn=i;
}
}
Abigail outo(){
if (tp<2) puts("There are no adjacent primes.");
else printf("%d,%d are closest, %d,%d are most distant.\n",p[mn],p[mn+1],p[mx],p[mx+1]);
for (int i=1;i<=r-l+1;++i)
cnt[i]=0;
tp=0;
}
int main(){
sieve(N);
while (~scanf("%d%d",&l,&r)){
work();
outo();
}
return 0;
}