题411.筛质数-acwing-196. 质数距离
一、题目
二、题解
本题让你找到[l,r]区间中相邻质数差值最小的一对和最大的一对,一般想法就是筛出[0,r]内的所有质数,然后相邻质数成对判断,但是由于l、r的数据范围最大可达231-1,大概为109级别的数,那么用O(n)的欧拉筛开数组存质数和标记合数肯定是开不下且太慢了,所以得想着怎么去巧妙地处理这个筛质数问题。
我们知道一个合数的最小质因子一定会小于sqrt(这个数),那么最大109级别的数其实开根号之后也就5e4这么大,那么它必定可用[0,5e4]范围的质数的求倍数得到,从而被筛出来。
对此,我们可以每次先预处理出5e4范围内的所有质数,然后去枚举这些质数,利用这些质数的倍数筛出[l,r]区间内的合数,之后剩下没有做过合数标记的数即为质数将它们打入质数表中,最后挨对遍历求最大和最小即可。
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+1;
int vis[maxn],cnt;
ll p[maxn];
void isPrime(int n)
{
memset(vis,0,sizeof vis);
cnt=0;
for(int i=2;i<=n;i++)
{
if(!vis[i]) p[++cnt]=i;
for(int j=1;j<=cnt;j++)
{
if(i*p[j]>n) break;
vis[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
int main()
{
int l,r;
while(cin>>l>>r)
{
isPrime(5e4);
memset(vis,0,sizeof vis);
for(int i=1;i<=cnt;i++)
{
//[l,r]中的合数的质因数一定会在[0,50000]筛出来的质因数中,所以用每个p0的倍数筛出[l,r]中的合数
ll p0=p[i];
for(ll j=max(p0*2,(l+p0-1)/p0*p0);j<=r;j+=p0)
{
vis[j-l]=1;//因为l、r很大,所以将l代替0看作原点,然后用可行的下标对应的vis记下合数
}
}
cnt=0;
for(int i=0;i<=r-l;i++)
{
if(!vis[i]&&i+l>=2)//注意1不是质数
{
p[++cnt]=i+l;
}
}
if(cnt<2) cout<<"There are no adjacent primes."<<endl;
else
{
int minpos=0,maxpos=0;
for(int i=1;i+1<cnt;i++)
{
int d=p[i+1]-p[i];
if(d<p[minpos+1]-p[minpos]) minpos=i;
if(d>p[maxpos+1]-p[maxpos]) maxpos=i;
}
printf("%d,%d are closest, %d,%d are most distant.\n",p[minpos],p[minpos+1],p[maxpos],p[maxpos+1]);
}
}
}