【大区间质数 合数标记】 prime distance
传送门
题意
给定两个整数\(l,r\),求在\([l,r]\)区间内距离最近的一对相邻质数,和距离最远的一对相邻质数
数据范围
\(l,r \in [1 , 2^{31}-1]\)
其中\(r-l \leq 10^{6}\)
题解
\(l,r\)的范围很大,大约是\(2\times 10^{9}\),线性算法也无法求出\([1,r]\)的所有质数,但是\(r-l\)的范围小,
通过\(x-l\)来映射\(l\sim r\)之间的每一个数字
任何一个合数必定会包含一个不超过 \(\sqrt{n}\)的质因数,所以求出 \(2\sim \sqrt{r}\) 的所有质数,
-
对于每个质数,将\([l,r]\)中能整除这个数字的标记,剩下的就是区间内的质数。
-
找到\(\geq l\)的关于\(p\)的倍数,即为\(\lceil \frac{L}{p}\rceil \times p\)
-
在标记合数的时候需要取\(max(2\times p ,\lceil \frac{L}{p}\rceil \times p)\),因为\(p\)是素数不能被标记为合数
-
对于所有质数两两求距离,最后求最值即可
时间复杂度 :
-
$ = \sqrt{r} + (\frac{r-l}{2} + \frac{r-l}{3} + \dots + \frac{r-l}{r-l})$
-
\(=\sqrt{r} + (r-l) \times (\frac{1}{2} + \frac{1}{3} + \dots + \frac{1}{r})\)
- \(\frac{1}{2} + \frac{1}{3} + \dots + \frac{1}{r-l}\approx log(log(r-l))\)
即\(O (\sqrt{r} \times log (log (r-l)))\)
Code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define ll long long
const int N=1e6+10;
ll l,r;
int primes[N],cnt;
bool st[N];
bool f[N];
int ans[N];
void get_primes(int n)
{
rep(i,2,n+1)
{
if(!st[i]) primes[++cnt]=i;
for(int j=1;primes[j]<=n/i;j++)
{
st[primes[j]*i]=1;
if(i%primes[j]==0) break;
}
}
}
void solve()
{
get_primes(sqrt(r));
memset(f,0,sizeof f);
rep(i,1,cnt+1)
{
ll p=primes[i];
// 求出 l~r关于当前素数的起点
for(ll j=max(2*p,(l+p-1)/p * p);j<=r ;j+=p)
f[j-l] = 1;
}
int num=0;
rep(i,0,r-l+1)
{
if(!f[i] && i+l>1) // 特判1被标记的情况
ans[++num] = i+l;
}
if(num<2) cout<<"There are no adjacent primes."<<endl;
else
{
int mx=1,mi=1;
rep(i,1,num)
{
int dis=ans[i+1]-ans[i];
if(dis>ans[mx+1]-ans[mx]) mx=i;
if(dis<ans[mi+1]-ans[mi]) mi=i;
}
cout<<ans[mi]<<","<<ans[mi+1]<<" are closest, "<<ans[mx]<<","<<ans[mx+1]<<" are most distant."<<endl;
}
}
int main()
{
while(cin>>l>>r) solve();
}

浙公网安备 33010602011771号