题目链接: 传送门
题目大意: 给你L和R两组数,L和R的范围是2^32,其间隔(即R-L最大为1,000,000.) 。让你求出L和R之间素数的最大间隔和最小的间隔。
比如 2 17。之间的最小素数间隔是2 3,最大的素数间隔是11 17。
要是直接进行一个2^32次方筛法然后在判断是会T的。
我们这样来想,筛法求素数的原理是什么:
/**vis数组标记为0则说明是素数*/
int vis[10005];
void getPrimevis(int n)
{
int m=sqrt(n+0.5);
memset(vis,0,sizeof(vis));
for(int i=2; i<=m; i++)
for(int j=i*i; j<=n; j+=i) vis[j]=1;
}
我们只用找到m=sqrt(n)内的素数和合数,然后对于1~n中的数如果输1~m中的
素数的倍数,则筛掉。
则判断L到R中素数的个数就也不是很难了。
对于这个题目来说
先把m=sqrt(n)中的素数和合数都求出来,对于L~R中的数进行一个判断。比如让你求1000到2000的结果。
先把1000/c[i]的值记为s,在吧2000/c[i]的值记为t,然后对于s到t之间我们用相应的素数c[i]乘s 到 相应的素数c[i]乘t 得到的值减去1000(这样有助于减少数组的大小)。
这样就把L~R的数组转换成了r数组,下面就是一个暴力的搜的过程了。
主要是一些细节的处理,比如1的处理,边界情况的处理,自己向来这种题目写的蛋疼......
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstring>
#include<iostream>
#include<stdio.h>
#include<cstdlib>
#include<functional>
#include<cmath>
#define LL long long
using namespace std;
const int N=50000;
int Max=0xfffffff;
int a[50100];
int r[1000000],b[N+100],z=0;
int main()
{
int a0,b0,i,j;
for (i=2; i<=N; i++)
if (!a[i])
{
b[++z]=i;
for (j=i*2; j<=N; j+=i) a[j]=1;
}
while (cin>>a0>>b0)
{
memset(r,0,sizeof(r));
int t=0,dis,mmax=-1,mmin=Max,m1,m2;
for (i=1; i<=z; i++)
{
int s,t;
s=(a0-1)/b[i]+1;
t=b0/b[i];
for (j=s; j<=t; j++)
if (j>1) r[j*b[i]-a0]=1; //利用1~50000中的素数,把合数筛掉,转换成r数组
}
int k=-1;
for (i=0; i<=b0-a0; i++)
if (!r[i]) //若是质数
{
if (k!=-1)
{
dis=i-k;
if (dis>mmax)
mmax=dis,m1=i+a0;
if (dis<mmin)
mmin=dis,m2=i+a0;
}
if (i+a0!=1) k=i; //跳过1
}
if (mmax<0)
cout<<"There are no adjacent primes."<<endl;
else
{
cout<<m2-mmin<<','<<m2<<" are closest, ";
cout<<m1-mmax<<','<<m1<<" are most distant."<<endl;
}
}
return 0;
}