【ybtoj高效进阶6-2-2】质数距离
给出一道仅仅只是输出不同的题目:
【luogu P1835】 素数密度
题目大意:
给你一个区间,让你输出这个区间中找到两个相邻质数,令它们的差有最大值和最小值,输出这两个质数。
然后区间的左右端点
L
,
R
<
=
2
31
−
1
,
R
−
L
<
=
1
0
6
L,R<=2^{31}-1,R-L<=10^6
L,R<=231−1,R−L<=106
思路:
看到此题的第一个想法是求出区间
[
1
,
R
]
[1,R]
[1,R]的所有质数,然后在
[
L
,
R
]
[L,R]
[L,R]中寻找符合条件的质数。
然后
R
<
=
2
31
R<=2^{31}
R<=231,最快的线性筛的时间复杂度也要
O
(
N
)
O(N)
O(N),很明显也无法在规定时间内求出所有质数(当然打表除外)
但是我们不需要求出所有的质数,我们只关心
[
L
,
R
]
[L,R]
[L,R]中的所有质数,而我们知道,在筛法的过程中,每一个合数
x
~~x~~
x 都会在
x
\sqrt x
x之内被某一个数标记,那么这启发我们只需要求出
[
1
,
R
]
[1,\sqrt R]
[1,R]的所有质数,然后用这些质数在区间
[
L
,
R
]
[L,R]
[L,R]将其所有的整数倍数进行标记,最后那些剩下的数就是质数了,然后把它们映射到一个下表为
[
1
,
p
r
i
m
e
(
L
,
R
)
]
[1,prime(L,R)]
[1,prime(L,R)]的数组中,
p
r
i
m
e
(
L
,
R
)
prime(L,R)
prime(L,R)表示
[
L
,
R
]
[L,R]
[L,R]中质数的个数。
然后从前往后一个个判断即可。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
const ll V=1e7+10;
ll le,ri,p[V],ans[V],tot,n,top;
bool val[V],pd[V];
void get_prime()
{
rep(i,2,n)
{
if(!val[i]) p[++top]=i;
for(r ll j=1;i*p[j]<=n&&j<=top;++j)
{
val[i*p[j]]=true;
if(i%p[j]==0) break ;
}
}
}
int main()
{
while(scanf("%lld%lld",&le,&ri)!=EOF)
{
memset(p,0,sizeof(p));
memset(val,false,sizeof(val));
memset(ans,0,sizeof(ans));
memset(pd,false,sizeof(pd));
tot=top=0;
n=sqrt(ri);
get_prime();
if(le==1) ++le;
rep(i,1,top)
rep(j,(le-1)/p[i]+1,ri/p[i])
if(j>1) pd[j*p[i]-le]=true ;
rep(i,le,ri)
if(!pd[i-le]) ans[++tot]=i;
if(tot<2)
{
printf("There are no adjacent primes.\n");
continue ;
}
ll preb,pres,nowb,nows;
preb=pres=ans[1],nowb=nows=ans[2];
rep(i,3,tot)
{
if(ans[i]-ans[i-1]>nowb-preb)
preb=ans[i-1],nowb=ans[i];
if(ans[i]-ans[i-1]<nows-pres)
pres=ans[i-1],nows=ans[i];
}
printf("%lld,%lld are closest, %lld,%lld are most distant.\n",pres,nows,preb,nowb);
}
return 0;
}
然后洛谷那道题就改一下输出就可以了