poj 2689 Prime Distance (double筛筛出大素数)

题意:给两个数L,U,1<=L< U<=2,147,483,647,求在L,U间的两相邻素数最小距离和最大距离。

          距离的定义就是俩数相减绝对值。

          The difference between L and U will not exceed 1,000,000.


解析:范围太大了,无法一次性筛出大素数,由题中L与U间范围为1000000找切入点,即筛出L与U间的素数,再O(n)扫一遍。

          先筛出小素数,然后用小素数为基,筛出大素数,筛法异曲同工。

          筛小素数时先假设所有数都为素数,接下来定下一个素数,此素数的倍数全不为素数。

          大素数大概为8000多个,渐进复杂度 x / lnx 可以计算出来。

          筛大素数时同理,先假设全为素数,接下来先由小素数的倍数扫一遍筛出不为素数的,再由余下为素数的扫一遍筛出不为素数的数。


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = 4 * atan(1.0);
const double ee = exp(1.0);

LL lo, hi;

const int maxs = 5e4 + 10;
LL smallPrime[maxs];
bool isSmallPrime[maxs];
int nSmallPrime;

void doSmallPrime()
{
    memset(isSmallPrime, true, sizeof(isSmallPrime));
    nSmallPrime = 0;
    for (LL i = 2; i < maxs; i++)
    {
        if (isSmallPrime[i])
        {
            smallPrime[++nSmallPrime] = i;
            for (LL j = i * i; j < maxs; j += i)
            {
                isSmallPrime[j] = false;
            }
        }
    }
}

const int maxb = 1e6 + 10;
LL bigPrime[maxb];
bool isBigPrime[maxb];
int nBigPrime;

void doBigPrime()
{
    memset(isBigPrime, true, sizeof(isBigPrime));
    for (LL i = 1; i <= nSmallPrime; i++)
    {
        LL t = lo / smallPrime[i];
        while (t * smallPrime[i] < lo || t <= 1)
        {
            t++;
        }
        for (LL j = t * smallPrime[i]; j <= hi; j += smallPrime[i])
        {
            if (lo <= j)
            {
                isBigPrime[j - lo] = false;
            }
        }
    }
    if (lo == 1)
        isBigPrime[0] = false;
    nBigPrime = 0;
    for (LL i = 0; i <= hi - lo; i++)
    {
        if (isBigPrime[i])
        {
            bigPrime[++nBigPrime] = i + lo;
        }
    }
}

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    doSmallPrime();
    while (scanf("%lld%lld", &lo, &hi) == 2)
    {
        doBigPrime();
        if (nBigPrime <= 1)
            printf("There are no adjacent primes.\n");
        else
        {
            LL minn = inf, maxx = 0;
            LL minl = -1, minr = -1;
            LL maxl = -1, maxr = -1;
            for (int i = 1; i < nBigPrime; i++)
            {
                if (bigPrime[i + 1] - bigPrime[i] < minn)
                {
                    minn = bigPrime[i + 1] - bigPrime[i];
                    minl = bigPrime[i], minr = bigPrime[i + 1];
                }
                if (maxx < bigPrime[i + 1] - bigPrime[i])
                {
                    maxx = bigPrime[i + 1] - bigPrime[i];
                    maxl = bigPrime[i], maxr = bigPrime[i + 1];
                }
            }
            printf("%lld,%lld are closest, %lld,%lld are most distant.\n", minl, minr, maxl, maxr);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值