https://oj.shiyancang.cn/Problem/781.html
素数距离,数据范围21亿,如果用素数筛存,并且进行做的话,按照x/lnx计算会是一个非常恐怖的复杂度。确定要做什么,首先一定要筛选素数,然后一定要进行素数的比较。问题就在筛选素数这里,可以看到区间范围很小,可以从这里入手,怎么储存,不可能按照那个储存,可以进行离散化,或者偏移,等等注意1的存在,无法被素数筛选掉,注意越界问题,那么就是区间素数筛选,埃氏筛的使用。因为算数基本定理,必然有小于sqrt的素数因子,这是可以接受的。那么sqrt再x、lnx就会很小了,每次一个1e4的复杂度直接解决了,求出a,b.储存上一状态的量,逐一比较即可。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=1e5+520; const ll INF=0x3f3f3f3f; ll prime1[N],cnt,prime2[N*10],l,r; bool st[N*10]; void get_prime(ll n) { for(int i=2;i<=n;i++) { if(!st[i]) prime1[cnt++]=i; for(int j=0;prime1[j]<=n/i;j++) { st[prime1[j]*i]=1; if(i%prime1[j]==0) break; } } } void get_prime2() { ll a,b; memset(st,0,sizeof(st)); for(ll i=0;i<cnt;i++)//要么刚好,要么卡进区间, 但是如果是1的话,那么意味着没有任何一个可以通过素数筛选掉他 { a=(l-1)/prime1[i]+1,b=r/prime1[i];//向上进位, //prime卡进区间范围内,(l-1)卡进里面去,但是L是从零开始的了 for(ll j=a;j<=b;++j) { if(j>1) { st[prime1[i]*j-l]=1; } } //压缩储存,区间长度很小 } if(l==1) st[0]=1; } void solve () { ll minn=INF,maxn=-INF; ll minl,minr,maxl,maxr; get_prime2(); ll p=-1; for(int i=0;i<=r-l;i++) { if(!st[i])//只需要记录前面和后面就可以了 { if(p!=-1) { if(maxn<i-p) maxn=i-p,maxl=p,maxr=i;//类似神奇的幻方,只需要记录前一状态即可 if(minn>i-p) minn=i-p,minl=p,minr=i; } p=i;//每次做完都要更新,而不是第一次更新,因为相邻 } } //通过状态有没有更新,来判断是否具有结果 if(maxn==-INF)printf("There are no adjacent primes.\n"); else printf("%lld,%lld are closest, %lld,%lld are most distant.\n",minl+l,minr+l,maxl+l,maxr+l); // if(cnt2<=1) cout<<"There are no adjacent primes.\n"; // else // { // for(int i=0;i<cnt2;i++) // { // if(prime2[i+1]-prime2[i]<minn) // { // minn=prime2[i+1]-prime2[i]; // minl=prime2[i],minnr=prime1[i+1]; // } // if(prime2[i+1]-prime2[i]>maxn) // { // maxn=prime2[i+1]-prime2[i]; // maxl=prime2[i],maxr=prime1[i+1]; // } // } // printf("%lld,%lld are closest, %lld,%lld are most distant.\n",minl,minr,maxl,maxr); // } } int main() { get_prime(N); while(~scanf("%lld%lld",&l,&r))solve(); return 0; }