POJ2689 Prime Distance 素数距离

题目链接:http://poj.org/problem?id=2689


题目大意:

    数论是数学的一个分支,是研究数的性质。其中素数领域的研究几千年来一直吸引着人们的注意力。一个素数的除了自己和1以外没有别的整数可以整除它的数,最开始的素数有2,3,5,7等,但很快将变得很稀疏。一个有趣的问题是素数在不同范围内的密度。相邻素数是两个素数之间没有别的素数,如2和3就是相邻素数。

    该程序将输入两个数,L和U(1<=L<U<=2 147 483 647),要找出两个相邻素数C1和C2(L<=C1<C2<=U)是距离最小的(也就是说C2-C1最小)。如果最下距离的相邻素数不唯一,选择最初的。还需要找出两个相邻素数D1和D2(L<=D1<D2<=U)是距离最大的(同样在有多对的情况下选择最初的)。

输入:

    每行两个正整数L和U,其中L和U的差不超过1 000 000。

输出:

    对于每组L和U,如果没有相邻素数输出There are no adjacent primes.否则输出给定的两个相邻的素数。

输入样例:

    2   17

    14  17

输出样例:

    2,3 are closest, 7,11 are most distant.

    There are no adjacent primes.


分析:

    其实本题的思路很明确:在给定范围内,找出期间所有的素数,然后把素数间的最大距离、最小距离找出来。

    显而易见,找出一个区间的所有素数要用到筛法,但具体到本题,因为数据区间上限达到21亿,不能将这区间所有的素数存下来,只能针对本题区间长度小于1 000 000这一范围把给定区间内的素数筛出来。

    使用筛法筛掉区间[ L,U ]内的所有非素数因子(因为一个非素数是被它最小的素因子筛掉的),2 147 483 647内的数或者是素数,或者是能被sqrt(2 147 483 647)≈46341内的素数整除,也就是说,区间[ L,U ]内的所有非素数因子都在46341内。

    预先打印46341内的所有素数,然后用这些素数去筛掉制定区间内的所有非素数。

    根据素数分布定理:1 000 000个数中最多有80 000(≈n/ln(n))个素数。



实现代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define maxn 50000
#define INF 0x7fffffff
int prime1[maxn],nprime1;
bool isprime[maxn*20];
void init_prime1()
{
    long long i,j;
    nprime1=0;
    memset(isprime,1,sizeof(isprime));
    for(i=2;i<maxn;i++)
      if(isprime[i])
      {
          prime1[++nprime1]=i;
          for(j=i*i;j<maxn;j+=i)
            isprime[j]=0;
      }
}
long long l,u;
long long prime2[1000001];
int nprime2;
void init_prime2()
{
    long long i,j,b;
    memset(isprime,1,sizeof(isprime));
    for(i=1;i<=nprime1;i++)
    {
        b=l/prime1[i];
        while(b*prime1[i]<l||b<=1)
          b++;
        for(j=b*prime1[i];j<=u;j+=prime1[i])
          if(j>=l) isprime[j-l]=0;
    }
    if(l==1) isprime[0]=0;
}
void solve()
{
    long long ans_min=INF,ans_max=-INF;
    long long minl,minr,maxl,maxr;
    init_prime2();
    nprime2=0;
    for(int i=0;i<=u-l;i++)
      if(isprime[i])
        prime2[++nprime2]=i+l;
    if(nprime2<=1)
      puts("There are no adjacent primes.");
    else
    {
        for(int i=1;i<nprime2;i++)
        {
            if(prime2[i+1]-prime2[i]<ans_min)
            {
                ans_min=prime2[i+1]-prime2[i];
                minl=prime2[i];
                minr=prime2[i+1];
            }
            if(prime2[i+1]-prime2[i]>ans_max)
            {
                ans_max=prime2[i+1]-prime2[i];
                maxl=prime2[i];
                maxr=prime2[i+1];
            }
        }
        printf("%lld,%lld are closest, %lld,%lld are most distant.\n",minl,minr,maxl,maxr);
    }
}
int main()
{
    init_prime1();
    while(scanf("%lld%lld",&l,&u)!=-1)
      solve();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值