Prime Distance(poj2689变形的筛法素数)

题意:给你一个区间L,U计算这个区间里面的间距最大的连续素数和最小的连续素数1<=L< U<=2,147,483,647,L,U的间距不超过1000000.

思路:L,U的范围太大了无法使用普通的筛法,将所有素数全部筛完,但是因为它是L,U的一个区间,长度不超过10^6,那可以筛出这个区间的所有素数,然后再求最大最小间距

怎么求L,U区间的素数呢?

我们可以先看1<=L< U<=2,147,483,647这个区间的素数,最大的因子也就是根号2,147,483,647 = 47000,根据筛法的操作,先把2花圈,然后删除2的其他倍数,然后3花圈,删除3的其他倍数,一直删到根号2,147,483,647这个区间就只剩下素数了。

关键是怎么确定开始的L开始的2,3,5....的倍数,这时我们可以用 整数的强制转换 L / prime[i] * prime[i] 这样就正好转换为正好是要删除的prime[i]的倍数,但是还有一点这个开始的数要不小于L,要不去了也没用不在区间里,如果他小于L,继续加prime[i],如果正好整除prime[i]不要删除,素数除以它本身,即它是花圈的那个数,让它从下一个开始,一定记住从花圈的下一个数开始。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

long long p[1000008];
long long pp[1000008];
bool prim[1000008];
bool fp[1000008];
long long Isp()
{
    long long k = 0;
    prim[0] = prim[1] = 1;
    memset(prim,0,sizeof(prim));
    for(long long i = 2; i <= 47000; i++)
    {
        if(!prim[i])
        {
           p[k++] = i;
           for(long long j = i*i; j <= 47000; j += i)
           {
               prim[j] = 1;
           }
        }
    }
    return k;
}
void fun(long long L,long long U,long long cnt)
{
    long long i,j,b,k = 0;
    memset(fp,1,sizeof(fp));
    for(i = 0; i < cnt; i++)
    {
        b = L / p[i];
        while(b*p[i] < L || b <= 1)
            b++;
        for(j = b*p[i]; j <= U; j+=p[i])
        {
            fp[j-L] = 0;
        }
        if(L == 1)
            fp[0] = 0;
    }
}
int main()
{
    long long U,L;
    long long cnt = Isp();
    while(scanf("%I64d%I64d",&L,&U) != EOF)
    {
        long long sum = 0;
        fun(L,U,cnt);
        int Max = -999999,Min = 9999999;
        long long flagMax = 0,flagMin = 0;
        for(long long i = 0; i <= U-L; i++)
        {
            if(fp[i])
            {
                pp[sum++] = L+i;
            }
        }
        if(!sum || sum == 1)
        {
            printf("There are no adjacent primes.\n");continue;
        }
        for(int i = 0; i < sum-1; i++)
        {
            if(pp[i+1] - pp[i] > Max)
            {
                Max = pp[i+1] - pp[i];flagMax = i;
            }
            if(pp[i+1] - pp[i] < Min)
            {
                Min = pp[i+1] - pp[i];flagMin = i;
            }
        }
        printf("%I64d,%I64d are closest, %I64d,%I64d are most distant.\n",pp[flagMin],pp[flagMin+1],pp[flagMax],pp[flagMax+1]);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值