[题解] POJ2689 [质数距离]

质数距离

题目TP门

题目描述

给定两个整数L和R,你需要在闭区间[L,R]内找到距离最接近的两个相邻质数C1和C2(即C2-C1是最小的),如果存在相同距离的其他相邻质数对,则输出第一对。

同时,你还需要找到距离最远的两个相邻质数D1和D2(即D1-D2是最大的),如果存在相同距离的其他相邻质数对,则输出第一对。

输入格式

每行输入两个整数L和R,其中L和R的差值不会超过1000000。‘

输出格式

对于每个L和R ,输出一个结果,结果占一行。

结果包括距离最近的相邻质数对和距离最远的相邻质数对。(具体格式参照样例)

如果L和R之间不存在质数对,则输出“There are no adjacent primes.”。

样例

样例输入

2 17
14 17

样例输出

2,3 are closest, 7,11 are most distant.
There are no adjacent primes.
数据范围

1≤L<R≤2147483647

解析

L,R范围很大,即使是线性筛法也无法在有限时间内筛选出质数。
我们知道,在任何一个合数n中,必有一个小于sqrt(n)的因子。
所以先用任意筛法(时间复杂度<=O(n))筛出所有在sqrt( R )中的质数。
把这些数记为p。


不难想到,在[L,R]中的数,只要不被p整除,就是质数。找出[L,R]中的质数之后,后面的操作就很简单了。
于是我就想到了枚举L~R中所有的数,能否被P整除

代码如下
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
using namespace std;
#define ll long long
const ll MAXN = 1e7 + 5;
vector<ll> zs;
bool f[MAXN];
ll ans1, ans2, ans3, ans4, maxn, minn;
ll l, r, size;
void Sqrt_R() {
    ll i, j;
    f[1] = 1;
    size = 0;
    zs.clear();
    for (i = 2; i <= sqrt(r); i++) {
        if (f[i])
            continue;
        zs.push_back(i);
        for (j = 1; j <= sqrt(r) / i; j++) f[i * j] = 1;
    }
}
void Prime_Number() {
    ll i, j;
    ll last, l1, cnt = 0;
    minn = 0x3f3f3f3f;
    maxn = -minn;
    for (i = l; i <= r; i++) {
        bool flag = 0;
        for (vector<ll>::iterator it = zs.begin(); it != zs.end(); it++) {
            if (i % (*it) == 0) {
                flag = 1;
                break;
            }
        }
        if (i >= 2 && i <= sqrt(r))
            if (flag && (!f[i]))
                continue;
        if (flag && (!(i >= 2 && i <= sqrt(r))))
            continue;
        cnt++;
        if (cnt >= 2) {
            ll min1 = i - last;
            if (min1 < minn) {
                ans1 = l1;
                ans2 = i;
                minn = min1;
            }
            ll max1 = i - last;
            if (max1 > maxn) {
                ans3 = l1;
                ans4 = i;
                maxn = max1;
            }
        }
        last = i;
        l1 = i;
    }
    if (cnt >= 2)
        printf("%lld,%lld are closest, %lld,%lld are most distant.\n", ans1, ans2, ans3, ans4);
    else
        printf("There are no adjacent primes.\n");
}
int main() {
    while (scanf("%lld %lld", &l, &r) != EOF) {
        memset(f, 0, sizeof(f));
        Sqrt_R();
        Prime_Number();
    }
    return 0;
}

这种的时间复杂度是O((L-R)*sqrt( R)),于是,我超时了。
在这里插入图片描述
于是在上述方法的改进下,在找p的时候,把[L,R]中能整除p的数标记了,时间复杂度就可以减少到O(L-R),就不会超时。

正解
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
using namespace std;
#define ll long long
const ll MAXN = 1e7 + 5;
bool f[MAXN], p[MAXN];
ll ans1, ans2, ans3, ans4, maxn, minn;
ll l, r;
void Sqrt_R() {
    ll i, j;
    f[1] = 1;
    for (i = 2; i <= sqrt(r); i++) {
        if (f[i])
            continue;
        ll u = (l - 1) / i + 1;
        while ((u * i) < l) u++;
        if (u < 2)
            u = 2;
        while ((u * i) <= r) {
            p[(u * i) - l] = 1;
            u++;
        }
    }
}
void Prime_Number() {
    ll i, j;
    ll last, l1, cnt = 0;
    minn = 0x7fffffff;
    maxn = -minn;
    for (i = l; i <= r; i++) {
        if (!p[i - l] && i != 1) {
            if (i - last < minn && cnt != 0) {
                minn = i - last;
                ans1 = last;
                ans2 = i;
            }
            if (i - last > maxn && cnt != 0) {
                maxn = i - last;
                ans3 = last;
                ans4 = i;
            }
            last = i;
            cnt++;
        }
    }
    if (cnt >= 2)
        printf("%lld,%lld are closest, %lld,%lld are most distant.\n", ans1, ans2, ans3, ans4);
    else
        printf("There are no adjacent primes.\n");
}
int main() {
    while (scanf("%lld %lld", &l, &r) != EOF) {
        memset(f, 0, sizeof(f));
        memset(p, 0, sizeof(p));
        Sqrt_R();
        Prime_Number();
    }
    return 0;
}

这道题用了埃氏筛法的思想。
单独来看,筛选1-n中的质数,时间复杂度只有O(n*log(n)),是竞赛中最常用的质数筛法。
在这里插入图片描述

posted @ 2020-10-30 21:30  Last_Breath  阅读(235)  评论(0编辑  收藏  举报