素数筛 -- 埃氏筛 欧拉筛 详解

素数筛

什么是质数?

若a ,b 除±1外无其他公因数,则称a和b互质。

定理1(算术基本定理)

任意正整数n(n != 1)恰有一种方法写成质数的乘积(不计因数乘积的顺序)

定理2(欧几里得)

质数无穷多


那么我们初学任意编程语言时,一定会遇到求素数的问题,我们朴素的方法一般都是暴力枚举

inline bool isprime(int x)
{
    for (int i = 2; i < x; i++)
        if (x % i == 0)
            return false;
    return true;
}

从2枚举到 x - 1,如果整除那么就不是素数

代码的正确性毫无疑问 , 但是如果需求量过大,效率就显得低下

这时有人会发现,我们没必要枚举到x - 1,我们只需要枚举到它的平方根即可

(小的那个因数整除,大的必然整除)

如此一来,代码就变成了这个样子

inline bool isprime(int x)
{
    int sq = (int)sqrt(x);
    for (int i = 2; i < sq + 1; i++)
        if (x % i == 0)
            return false;
    return true;
}

优化掉sqrt的二分快速幂的复杂度的话

inline bool isprime(int x)
{
    for (int i = 2; i <= x / i; i++)
        if (x % i == 0)
            return false;
    return true;
}

可这样仍然不能满足我们对于效率的要求,显然我们还要另寻出路。

空间换时间是我们算法优化中的一个重要思想,记忆化搜索就是该思想的一种应用

我们每判定出一个素数,对于这个素数乘上大于1的因子的数显然都是合数,如果我们能标记这些合数,我们就能省略去许多

不必要的判断

const int  maxn = 1e7 + 10;
int prime[maxn + 1];
inline bool isprime(int x)
{
    prime[2] = 0;
    for (int i = 2; i <= maxn / i; i++)
    {
        if (!prime[i])
            for (int j = i * i; j <= maxn; j += i)
                prime[j] = 1;
    }
    return !prime[x];
}

这就是我们的埃氏筛

这里解释为什么埃氏筛的j要从i * i而不是2 * i开始, 因为对于大于2的i , 任意 k * i(k < i)它一定在筛k 的 质因数的时候筛过了

这也是我们接下来进一步优化的思想

其实这样我们的时间优化已经大大提升了,可是我们发现我们对于每个合数都筛选到x这样一定有重复的情况

比如对于36 , 它可以被4筛 可以被9筛等等,就像kmp算法next数组优化为nextval一样, 我们的埃氏筛也有需要优化的地方

我们先上代码

const int  maxn = 1e7 + 10;
int primes[maxn + 1], cnt = 0;//0为素数 1为合数
int prime[maxn + 1];
inline bool isprime(int x)
{
    prime[2] = 0;
    for (int i = 2; i <= maxn; i++)
    {
        if (!prime[i])
            primes[cnt++] = i;
        for (int j = 0; j <= cnt && primes[j] * i < maxn; j++)
        {
            prime[primes[j] * i] = 1;
            if (i % primes[j] == 0)
                break;
        }
    }
    return !prime[x];
}

这就是素数筛的终极版--欧拉筛

那么为什么欧拉筛能保证每个合数都被筛且只被筛一次呢

还记得我们的定理1(算术基本定理)吗

定理1(算术基本定理)**

任意正整数n(n != 1)恰有一种方法写成质数的乘积(不计因数乘积的顺序)

欧拉筛法核心思想:每个合数只被自己的最小质因子筛一次。

我们prime[i]是从最小的素数开始枚举

i%prime[j] != 0 则说明prime[j]就是我的最小质因数

对 i%prime[j]==0 时即跳出循环的解释:此时可以令 i = k×prime[j],若不跳出,继续筛 i×prime[j+1] 的话,i×prime[j+1] = k×prime[j]×prime[j+1],它的最小质因子显然是 prime[j] 而不是 prime[j+1],违反了筛法原则。

这样就保证了每个合数被最小质因数筛选一次

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值