线性筛 + 埃式筛 (筛区间质数) - Prime Distance - POJ 2689

线性筛 + 埃式筛 (筛区间质数) - Prime Distance - POJ 2689

题意:

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

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

输入格式

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

输出格式

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

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

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

数据范围

1 ≤ L < U ≤ 2 31 − 1 1≤L1L<U2311

输入样例:

2 17
14 17

输出样例:

2,3 are closest, 7,11 are most distant.
There are no adjacent primes.

分析:

要 求 区 间 [ L , R ] 内 , 距 离 最 近 的 两 个 相 邻 质 数 和 距 离 最 远 的 两 个 相 邻 质 数 。 要求区间[L,R]内,距离最近的两个相邻质数和距离最远的两个相邻质数。 [L,R]

思 路 上 , 先 筛 出 这 段 区 间 内 的 质 数 , 再 遍 历 一 遍 求 相 邻 质 数 差 值 的 最 值 。 思路上,先筛出这段区间内的质数,再遍历一遍求相邻质数差值的最值。

难点:

线 性 筛 是 筛 [ 1 , N ] 内 的 质 数 , L 和 R 的 范 围 将 达 到 1 0 9 , 无 论 是 从 时 间 上 还 是 空 间 上 考 虑 均 不 合 理 。 线性筛是筛[1,N]内的质数,L和R的范围将达到10^9,无论是从时间上还是空间上考虑均不合理。 线[1,N]LR109

但 是 , 区 间 的 长 度 不 超 过 1 0 6 , 但是,区间的长度不超过10^6, 106

对 于 每 个 合 数 X , 都 必 存 在 一 个 最 小 质 因 子 P , 对 应 的 还 有 另 一 个 因 子 X P , 对于每个合数X,都必存在一个最小质因子P,对应的还有另一个因子\frac{X}{P}, XPPX

而 X 的 最 小 质 因 子 P , 必 有 P ≤ X , 而X的最小质因子P,必有P≤\sqrt{X}, XPPX

所 以 , 我 们 可 以 先 筛 出 R 以 内 的 质 数 的 P i , 再 借 助 埃 氏 筛 法 的 思 想 , 筛 去 区 间 [ L , R ] 内 P i 的 倍 数 。 所以,我们可以先筛出\sqrt{R}以内的质数的P_i,再借助埃氏筛法的思想,筛去区间[L,R]内P_i的倍数。 R Pi[L,R]Pi

由 于 质 数 的 范 围 较 大 , 可 以 将 区 间 [ L , R ] 内 的 质 数 先 减 去 偏 移 量 L , 映 射 到 区 间 [ 0 , R − L ] 内 , 用 布 尔 数 组 标 记 。 由于质数的范围较大,可以将区间[L,R]内的质数先减去偏移量L,映射到区间[0,R-L]内,用布尔数组标记。 [L,R]L[0,RL]

细节:

埃 式 筛 法 : 对 每 一 个 质 数 P i , 筛 去 [ L , R ] 内 P i 的 倍 数 。 埃式筛法:对每一个质数P_i,筛去[L,R]内P_i的倍数。 Pi[L,R]Pi

如 何 计 算 出 第 一 个 大 于 等 于 L 的 P i 的 倍 数 ? 如何计算出第一个大于等于L的P_i的倍数? LPi

将 P i 扩 大 ⌈ L P i ⌉ 倍 , 且 至 少 两 倍 , 将P_i扩大\lceil\frac{L}{P_i}\rceil倍,且至少两倍, PiPiL

而 ⌈ L P i ⌉ = ⌊ L + P i − 1 P i ⌋ , 而\lceil\frac{L}{P_i}\rceil=\lfloor\frac{L+P_i-1}{P_i}\rfloor, PiL=PiL+Pi1

故 对 于 每 一 个 P i , 从 m a x ( 2 P i , ⌊ L + P i − 1 P i ⌋ ) 开 始 , 筛 掉 P i 的 倍 数 。 故对于每一个P_i,从max(2P_i,\lfloor\frac{L+P_i-1}{P_i}\rfloor)开始,筛掉P_i的倍数。 Pimax(2Pi,PiL+Pi1)Pi

时间复杂度分析:

线 性 筛 : 筛 出 R 以 内 的 质 数 , R 上 限 约 为 2.1 × 1 0 9 , 故 我 们 筛 出 50000 以 内 的 质 数 即 可 。 线性筛:筛出\sqrt{R}以内的质数,R上限约为2.1×10^9,故我们筛出50000以内的质数即可。 线R R2.1×10950000

埃 式 筛 : 筛 出 区 间 长 度 不 超 过 1 0 6 内 的 质 数 , 计 算 次 数 为 1 0 6 ( 1 2 + 1 3 + 1 5 + 1 7 + . . . ) , 时 间 复 杂 度 O ( n l o g ( l o g n ) ) 埃式筛:筛出区间长度不超过10^6内的质数,计算次数为10^6(\frac{1}{2}+\frac{1}{3}+\frac{1}{5}+\frac{1}{7}+...),时间复杂度O(nlog(logn)) 106106(21+31+51+71+...)O(nlog(logn))

当 n = 1 0 6 时 , l o g ( l o g n ) ≈ 5 , 最 终 的 时 间 复 杂 度 是 O ( n ) 级 别 的 。 当n=10^6时,log(logn)≈5,最终的时间复杂度是O(n)级别的。 n=106log(logn)5O(n)

代码:

#include
#include
#include

#define ll long long

using namespace std;

const int N=1e6+10;

int primes[50000],cnt;
bool st[N];

void get_prime(int n,int L,int R)   //二次筛法,筛出[L,R]内的质数
{
    memset(st,false,sizeof st);
    cnt=0;
    
    for(int i=2;i<=n;i++)   //预处理出[2,50000]内的质数,50000是大于sqrt(R)上界的一个数
    {
        if(!st[i]) primes[cnt++]=i;
        for(int j=0;primes[j]*i<=n;j++)
        {
            st[primes[j]*i]=true;
            if(i%primes[j]==0) break;
        }
    }
    
    memset(st,false,sizeof st); 
    for(int i=0;i<cnt;i++)
    {
        ll p=primes[i];
        ll start=max(2*p, (L+p-1)/p*p);
        for(ll j=start;j<=R;j+=p)
            st[j-L]=true;
    }
    
    cnt=0;
    for(int i=0;i<=R-L;i++)
        if(!st[i] && i+L>=2)
            primes[cnt++]=i+L;
}

int main()
{
    int l,r;
    while(~scanf("%d%d",&l,&r))
    {
        get_prime(50000,l,r);
        
        if(cnt<2) puts("There are no adjacent primes.");
        else
        {
            int maxp=0,minp=0;
            int maxd=0,mind=1e6;
            for(int i=0;i+1<cnt;i++)
            {
                int d=primes[i+1]-primes[i];
                if(d>maxd) maxd=d, maxp=i;
                if(d<mind) mind=d, minp=i;
            }
            
            printf("%d,%d are closest, %d,%d are most distant.\n",
                    primes[minp],primes[minp+1],primes[maxp],primes[maxp+1]);
        }
    }
    return 0;
}

你可能感兴趣的:(数论,算法,数论,埃式筛,线性筛,ACM)