【ybtoj】【质数和约数】质数距离

题意

image

题解

肯定和质数筛法有关,但是 \(l,r\) 都很大所以另辟蹊径。
这里有一个常用的切入点:\(l,r\) 之间的距离很小,所以考虑将区间整体左移 \(l\) 位,这样数组可以存下。
对于任何一个合数 \(n\) ,都有一个不超过 \(\sqrt{n}\) 的约数,用 \(j\times prime_i\) 筛掉 \([l,r]\) 区间内的素数。(\(\lceil l \rceil \le i \le r\) )
如此,复杂度已经降到 \(O(n+\log n\sqrt{n})\) .

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f,N = 1e6+10;
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
const int n = 1e6;
bool vis[N],v[N];
int pri[N],cnt;
ll tmp[N];
int l,r;
void deal_prime()
{
	for(int i=2;i<=n;i++)	
	{
		if(!vis[i]) pri[++cnt]=i;
		for(int j=1;j<=cnt&&i*pri[j]<=n;j++) 
		{
			vis[i*pri[j]]=1;
			if(i%pri[j]==0) break;
		}
	}
}
ll max1,max2,min1,min2;
void solve(int l,int r)
{
	memset(v,0,sizeof(v));
	memset(tmp,0,sizeof(tmp));
	int tcnt=0;
	if(l==1) l++;//特判 
	for(int i=1;i<=cnt;i++)
		for(int j=ceil(1.0*l/pri[i]);j<=r/pri[i];j++) 
		{
			if(j==1) continue;
			v[j*pri[i]-l]=1;
		}
	for(ll i=l;i<=r;i++)
		if(!v[i-l]) tmp[++tcnt]=i;
	if(tcnt<2) {printf("There are no adjacent primes.\n");return;}
	max1=min1=tmp[1],max2=min2=tmp[2];
	for(int i=3;i<=tcnt;i++) 
	{
		if(tmp[i]-tmp[i-1]>max2-max1) max2=tmp[i],max1=tmp[i-1];
		if(tmp[i]-tmp[i-1]<min2-min1) min2=tmp[i],min1=tmp[i-1];
	}
	printf("%lld,%lld are closest, %lld,%lld are most distant.\n",min1,min2,max1,max2);
	return;
}
int main()
{
	deal_prime();
	while(scanf("%d%d",&l,&r)!=EOF) solve(l,r);
	return 0;
}
posted @ 2021-09-24 17:32  conprour  阅读(30)  评论(0编辑  收藏  举报