您的位置:首页 > 其它

poj Prime Distance(暴力 二次筛法)

2014-05-17 21:35 309 查看
此题数据范围灰常大,输入范围高达int的最大值,故素数是不可能全部保存下来的。。借此机会学习了二次筛法,其实就是用n里面的所有合数可以被sqet(n)里面所有质数给筛掉的原理,故只需要先筛出2^16次方以下的素数就可以了,一直用的是最普通的筛法,找时间去学学线性筛法。。。筛完后,看输入进来的a,b,如果b小于2^16那就直接复制原来素数表里的,如果不是,就要通过素数表里的素数来筛了,具体方法是从第一个素数p开始,乘以大于等于a的最小值k,再在标记数组里标记(p*k-a)为1,k++,重复操作直到b为止。这样的好处在于标记数组是从0到b-a的就不会浪费空间,因为范围实在太大开不了2^32次方的数组,在下面找素数的时候第i位置标记是0,说明是素数就可以用i+a来得到素数的值。

还需要正确估计素数的多少,就要用到一个公式n个连续的数,素数的个数大概n/ln(n)。这个公式得出来的值n越大越精确。

AC代码:

#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<ctime>
using namespace std;
#define NMAX 50000
#define ll long long
bool mark[1000010];
int prime[7000],pp[80000];
int pprime()
{
int i,j,k,m = NMAX;
for(i = 2; i*i < m; i++)
{
for(j = i*i; j < m; j+=i)
mark[j] = true;
}
for(k = 0,i = 2; i < m; i++)
if(!mark[i]) prime[k++] = i;
return k;

}

int main()
{
//    freopen("input.txt","r",stdin);
//    freopen("o1.txt","w",stdout);
int n = pprime();
int a,b,i,j,k;
while(~scanf("%d %d",&a,&b))
{
int e,fmin,fmax,n2=0;
memset(mark,0,sizeof(mark));
if(b <= NMAX)
{
for(i = 0; prime[i] < a; i++);
for(n2 = 0; prime[i] <= b;)
pp[n2++] = prime[i++];
}

else
{
for(i = 0; i < n && prime[i]*prime[i] <= b; i++)
{
if(prime[i] >= a) k = 2;
else
{
k = a/prime[i];
if(prime[i]%2) k++;
}
while(k <= b/prime[i])//这里本来写的是k*prime[i]<b。但是会超int范围就改成除法了
{
mark[k*prime[i]-a] = 1;
k++;
}
}
for(i = 0; i <= b-a; i++)
if(!mark[i]) pp[n2++] = i+a;
}
e = n2;
if(e <= 1)
printf("There are no adjacent primes.\n");
else
{
int Min=1000000,Max=0;
for(i = e-1; i > 0; i--)
{
int temp = pp[i] - pp[i-1];
if(temp >= Max)
{
fmax = i-1;
Max = temp;
}
if(temp <= Min)
{
fmin = i-1;
Min = temp;
}
}
printf("%d,%d are closest, %d,%d are most distant.\n",pp[fmin],pp[fmin+1],pp[fmax],pp[fmax+1]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: