![](https://img-blog.csdnimg.cn/img_convert/ab7d1f6551482b12cefd049c08ebd5c9.png)
和洛谷的P1835 素数密度 基本上一样,L到U的范围给的小,但是U的极限区间很大,这样就不能用bool或者bitset去判断所有范围里面的素数,并且也不能用线性筛去跑,20个亿会超时。
所以我们需要根据几个定理去解决这个问题:
大于1的自然数,不是素数就是合数。
如果一个数n是合数,那么在区间[1,sqrt(n)]范围中必然有一个n的质因子。
所以用小区间的素数,去跑一遍大区间的合数,那么大区间剩下的数全都是素数。
(埃式筛)原理即:2是素数,那么4,6,8,10,都不是素数。对于这道题来说就是,2是素数,那么[L,U]区间是2的倍数的都不是素数。
所以还需要快速定位到[L,U]区间中第一个是小素数倍数。
设L为左端点,i为目标素数,start为第一个目标合数
画图可知当i<L时:
1、L是i的整数倍,start=L
2、L不是i的整数倍,start=L+(i-L%i),余数部分补足
当i>=L时:
start=2*i
AC代码
#include <bits/stdc++.h>
#define int long long int
using namespace std;
const int MAX= sqrt(INT_MAX);
int l,r,maxx,minn;
pair<int,int>dis,clo;
bitset<1000001>np;
vector<int>pr;
inline void pre(){//把[1,sqrt(2^31-1)]素数筛出来
for(int i=2;i<=MAX;++i){
if(!np[i]){
pr.push_back(i);
for(int j=i<<1;j<=MAX;j+=i)
np[j]=true;
}
}
}
inline void work(){
//特判l==1
l=l==1?2:l;
//初始化
np.reset();
maxx=INT_MIN;
minn=INT_MAX;
for(auto i:pr){//i在[l,r]中的倍数都不是素数
int start;
if(i<l){
if(l%i==0)start=l;
else start=l+i-l%i;
}else{
start=2*i;
}
for(int j=start;j<=r;j+=i)
np[j-l+1]=true;
}
bool first=false;
int pre,now,sub;
for(int i=l;i<=r;++i){//跑一遍[L,U]得出答案
if(!np[i-l+1]){
if(first){
pre=now;
now=i;
sub=now-pre;
if(sub<minn){
minn=sub;
clo.first=pre;
clo.second=now;
}
if(sub>maxx){
maxx=sub;
dis.first=pre;
dis.second=now;
}
}else{
now=i;
first=true;
}
}
}
if(maxx==INT_MIN){
printf("There are no adjacent primes.\n");
}else{
printf("%d,%d are closest, %d,%d are most distant.\n",clo.first,clo.second,dis.first,dis.second);
}
}
signed main(){
pre();
while(cin>>l>>r)work();
return 0;
}
捏马的...当时读入一直用while(scanf("%d %d",&l,&r))work();不知道哪里错了,找了半天,要写!=EOF或者在前面标上~。