POJ 2689 Prime Distance【区间筛素数】

题目链接

题目描述:

给定两个整数L, R(1 ≤ L ≤ R ≤ 2 31 2^{31} 231, R - L ≤ 1 0 6 10^6 106),求闭区间 [L, R] 中相邻两个质数差最大和最小为多少。


题解:

因为范围太大,就算欧拉筛也会TLE,但是区间范围比较小,又因为一个合数N,至少能被2到根号N的一个数整除,2到根号N的素数一定是区间[L, R]内合数的质因子,所以可以先筛出2到5e4( 2 31 2^{31} 231开方)的素数,然后让这些素数筛去区间 [L, R] 的合数,最后留下的就是素数。
本题有几个细节:(1)当L为1时,要将L赋值为2,因为L = 1没有意义(1不是素数),并且如果L = 1会导致数组 a a a (数组 a a a是筛后区间中的素数)中会包括1,这明显是不对的;(2) 当a = 1时,表示prime[i] > L,此时prime[i]可能在区间 [L, R] 中,所以如果 a 仍然从1开始的话会导致 done[1 * prime[i]]被标记,即prime[i]被标记为合数,这显然是不对的,所以当a = 1时,a 应该从2开始。


AC代码:

#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
// #include <unordered_set>
// #include <unordered_map>
#include <deque>
#include <list>
#include <iomanip>
#include <algorithm>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
//#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
//cout << fixed << setprecision(2);
//cout << setw(2);
const int N = 5e4 + 6, M = 1e9 + 7;

bool vis[N];
int prime[N];
int done[1000005];

int main() {
    //freopen("/Users/xumingfei/Desktop/ACM/test.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n = 5e4, cnt = 0;
    for (int i = 2; i <= n; i++) {
        if (vis[i] == 0)
            prime[cnt++] = i;
        for (int j = 0; j < cnt && prime[j] * i <= n; j++) {
            vis[prime[j] * i] = 1;
            if (i % prime[j] == 0) break;
        }
    }
    int l, r;
    while (cin >> l >> r) {
        memset(done, 0, sizeof(done));
        for (int i = 0; i < cnt; i++) {
            if (l == 1) l = 2;
            int a = (l - 1) / prime[i] + 1;
            int b = r / prime[i];
            if (a == 1) a = 2;
            for (int j = a; j <= b; j++) {
                done[prime[i] * j - l] = 1;
            }
        }
        vector<int> a;
        for (int i = 0; i <= r - l; i++) {
            if (done[i] == 0) a.push_back(i + l);
        }
        int size = (int) a.size(), mx = -1, mn = 1e9, l1, r1, l2, r2;
        for (int i = 1; i < size; i++) {
            if (a[i] - a[i - 1] > mx) {
                mx = a[i] - a[i - 1];
                l1 = a[i - 1], r1 = a[i];
            }
            if (a[i] - a[i - 1] < mn) {
                mn = a[i] - a[i - 1]; 
                l2 = a[i - 1], r2 = a[i];
            }
        }
        if (mx == -1) {
            cout << "There are no adjacent primes." << '\n';
        } else {
            cout << l2 << "," << r2 << " are closest, " << l1 << "," << r1 << " are most distant." << '\n';
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值