关于三种素数筛法

在许多题目中,质数筛都并不是一道题拿分的决定性因素,但用了好的筛法往往可以是时间复杂度锦上添花,争取高分。


原始筛法:

思路:

这种筛法也不能说是废的,起码它好理解,容易操作,适用于判断单个数字。

整体很好理解,从 2 2 2 一直到 n \sqrt{n} n ,若能除得尽其中任意一个数字,就不是质数。

代码:

bool prime(int n){
    for(int i=2;i<=sqrt(n);i++){
        if(n%i==0)return false;
    }
    return true;
}

埃氏筛法:

思路:

埃氏筛法利用了一个素数的倍数一定不是素数、任何一个合数可以表示成一个素数和另一个数乘积的性质。

对于一定的范围,先假定它们都是质数,然后从 2 2 2 开始,先判断如果是素数,把它在范围内的倍数乘积都筛去,以此类推循环至 s q r t ( n ) sqrt(n) sqrt(n) 即可。

代码:

void isprime_B(int b){
    memset(is_prime,true,sizeof(is_prime));//先假设都为素数
    for(int i = 2;i <= sqrt(b);i++){
        if(is_prime[i]){
            prime[q++] = i;
            for(int j = i*2;j <= b;j += i)is_prime[j] = false;
        }
    }

}

欧拉筛法:

思路:

看懂上面埃氏筛法的 DALAO 可以跳过此基础部分,直接看进阶部分。 \color{white}\colorbox{red}{看懂上面埃氏筛法的 DALAO 可以跳过此基础部分,直接看进阶部分。} 看懂上面埃氏筛法的 DALAO 可以跳过此基础部分,直接看进阶部分。

基础(埃氏筛法):

欧拉筛的主题思想就是每搜到一个质数,就把它的倍数标记为合数,并把它加入队列。

那么怎么判断搜到的是不是质数呢?总不可能暴力判断吧,如果用暴力,那么就喜获 TLE 一枚。

其实我们每搜到一个数,如果是质数,那么它的倍数(肯定是合数)就标记一下。
那么我们就能知道:对于每个我们搜到的数,如果它被打过标记,那么它就不是质数,否则它就是质数。

进阶:

我们用了一行代码来减少时间复杂度:

if(i%prime[j]==0)break;

怎么实现的呢?

对于一个数,它可能有不止一个质因子,那么根据上面那个埃氏筛法,它会把每一个质数的倍数都标记一遍,也就是说,一个合数,它可能被标记了好几次。

例:对于 14 14 14,它会在 2 2 2 时标记一次, 7 7 7 时标记一次。共标记了两次。

有了这个,就可以避免多余的计算了。

最后浅浅算一下复杂度:时间、空间复杂度为 O ( n ) O(n) O(n) N i c e Nice Nice,可以过数据,这种 O ( n ) O(n) O(n) 的算法对我这样的蒟蒻实在是太友好了。 Q W Q QWQ QWQ

代码:

void euler(){  //isprime[i]代表此数是否打了标记,prime[i]存储已搜到的质数
    memset(isprime,true,sizeof(isprime));
    isprime[1]=false;
    for(int i=2;i<=n;i++){
        if(isprime[i])prime[++cnt]=i;
        for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
            isprime[i*prime[j]]=false;
            if(i%prime[j]==0)break;
            // 最神奇的一句话,如果i整除prime[j],退出循环
            // 这样可以保证线性的时间复杂度
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值