通过埃式筛法筛选区间素数

例题POJ2689添加链接描述
我们通过要求得一个区间[L,R]内的素数,由于L和R的数值可能会很大,如果用传统的线性筛来求解的话,会导致的问题。为了能够解决这个矛盾,我们利用效率低一点的埃氏筛来完成该题。

埃式筛的基本原理是,对于数n,必然存在2~√n之间的质数p是n的因数,所以这些质数的倍数k*p必然是合数。所以我们需要枚举筛完这个区间所需要的质数,然后枚举它的倍数然后筛去以它为因数的合数,对于该题,我们只需要筛出50000以内的质数就够了,这一步可以借用前面的线性筛来完成。

由于,如果令一个整数为k=(L-1)/p,那么k*p就是小于L的最大p的最大倍数,那么(k+1)*p就是大于等于L的第一个合数。注意,由于我们是筛的合数,故作为起始点,k+1必然是大于等于2的,否则如果k=0,p就是一个质数,就会出现错误。所以,为了保证如果p>=L,k=0时不出错,最终的起始系数x=max(2,k+1)。

我们从x开始枚举,(x+1)*p,(x+2)*p…依次标记为合数,将所有可能的p都用来筛一遍,最终留下来的就是质数了。根据本题的题意,再将合题的质数选出来即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#define maxn 1000005
using namespace std;
typedef pair<long long,long long> P;
int check[maxn];
int prime[maxn];
int v[maxn];
int tot=0;
int fin()   //线性筛先得出所有用来筛选的质数
{
    for(int i=2;i<=50000;i++)
    {
        if(!check[i])
        {
            prime[tot]=i;
            tot++;
        }
        for(int j=0;j<tot&&prime[j]*i<=50000;j++)
        {
            check[prime[j]*i]=1;
            if(i%prime[j]==0)break;
        }
    }
}
pair<P,P> solve(long long L,long long R)
{
    memset(v,0,sizeof(v));
    for(int i=0;i<tot;i++)
    {
        for(long long j=max(2ll,(L-1)/prime[i]+1)*prime[i];j<=R;j+=prime[i])//埃氏筛筛选素数
        {
            v[j-L]=1;
        }
    }
    long long a=-1,b=-1,x=-1,y=-1,z=-1,d=maxn,f=-1;
    for(long long i=L;i<=R;i++)
    {
        if(v[i-L])continue;
        if(z==-1){z=i;continue;}
        if(i-z<d)
        {
            x=z;
            y=i;
            d=i-z;
        }
        if(i-z>f)
        {
            a=z;
            b=i;
            f=i-z;
        }
        z=i;
    }
    if(a==-1||b==-1||a==b)return make_pair(make_pair(-1,-1),make_pair(-1,-1));
    else return make_pair(make_pair(a,b),make_pair(x,y));
}
int main()
{
    long long L,R;
    fin();
    while(cin>>L>>R)
    {
        int u=0;
        if(R<2)u=1;
        L=max(2ll,L);
        pair<P,P>ans=solve(L,R);
        if(!u&&ans.first.first==-1)
        {
            cout<<"There are no adjacent primes."<<endl;
        }
        else
        {
            cout<<ans.second.first<<","<<ans.second.second<<" are closest, "<<ans.first.first<<","<<ans.first.second<<" are most distant."<<endl;
        }
    }
}
### 使用C语言在PTA平台上实现埃拉托斯特尼筛法求区间素数 埃拉托斯特尼筛法是一种高效的算法用于找出一定范围内的所有素数。对于给定的一个正整数n,该方法可以有效地找到小于等于n的所有素数[^1]。 为了实现在特定区间[m, n]内寻找素数的功能,在实际编程过程中通常会先创建一个布尔类型的数组`isPrime[]`来标记哪些数字是素数。初始情况下假设所有的数值都是素数(即设置为true),之后通过遍历并更新这个数组中的元素状态完成筛选过程。当处理较大区间的查询时,考虑到内存使用的效率问题,建议只开辟大小约为sqrt(n)+1的空间存储必要的标志位即可满足需求[^2]。 下面是一个具体的例子展示如何利用C语言编写程序以获取指定范围内所有质数: ```c #include <stdio.h> #include <string.h> #define MAXN 1000005 // 定义最大可能值加一作为上限 int prime[MAXN]; // 存储素数表 bool is_prime[MAXN]; // 判断是否为素数的辅助数组 void sieve(int max_val) { memset(is_prime, true, sizeof(bool)*(max_val+1)); int cnt = 0; for (long long i = 2; i <= max_val; ++i){ if (is_prime[i]){ prime[cnt++] = i; for (long long j=i*i;j<=max_val;j+=i) is_prime[j]=false; } } } // 找到m-n之间的所有素数 void find_primes_between_m_and_n(long m,long n){ bool mark[n-m+1]; memset(mark,true,sizeof(bool)*(n-m+1)); for (int p=0;p<MAXN && prime[p]*prime[p]<=n;++p){ long first_multiple=(m/prime[p])*prime[p]; if(first_multiple<m)first_multiple+=prime[p]; for(;first_multiple<=n;first_multiple+=prime[p]) mark[first_multiple-m]=false; if(first_modified==m)mark[0]=true; } printf("Primes between %ld and %ld:\n", m,n); for (long i=m;i<=n;++i) if (mark[i-m])printf("%ld ",i); } ``` 上述代码片段展示了完整的埃氏筛法逻辑以及针对任意两个边界值之间查找素数的具体操作。需要注意的是这里定义了一个较大的常量`MAXN`用来表示预估的最大输入规模,并据此分配相应的空间;而在具体应用中应当依据实际情况调整此参数取值[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值