[数学基础] 3 筛法

筛法,个人觉得在基础阶段牢固的掌握埃氏筛和欧拉筛就很好了。它们是很好用的工具,用途也很广泛,甚至会用在一些(我)意想不到的地方。

筛法

1. 埃氏筛

  • 主要思想:筛掉所有质数的倍数
  • 代码
// 为什么j可以从i*i开始?
// 假设i=7, 那么比i小的所有的质数, 已经把2*7,3*7,5*7这样的数筛掉了, 所有可以直接从7*7开始筛
void Eratosthenes(){
    for (int i=2;i<=n;++i) st[i] = 1;
    for (int i=2;i<=n;++i){
        if (st[i]){
            p[++cnt] = i;
            if ((ll)i*i > n) continue;
            for (int j=i*i;j<=n;j+=i){
                st[j] = false;
            }
        }
    }
}
  • 时间复杂度分析

    如果是筛所有的数的倍数,那么会筛\(\frac{N}{2}+\frac{N}{3}+...+\frac{N}{N}=N\times(\frac{1}{2}+\frac{1}{3}+...+\frac{1}{N})\) 次。

​ 由于调和级数\(1+\frac{1}{2}+\frac{1}{3}+...+\frac{1}{N}=ln(N+1)+r\)\(r\)为欧拉常数,\(r\approx 0.5772156649\)。因此,时间复杂度可近似为\(O(NlnN)<O(NlogN)\)

​ 当只筛质数时,由质数分布定理可得\(N\)中约有\(\pi(N)=\frac{N}{ln N}\)个质数,因此时间复杂度估算结果为\(O(\frac{NlnN}{lnN})\),即非常接近\(O(N)\)。在实际计算下,埃氏筛的时间复杂度为\(O(NloglogN)\)

2. 欧拉筛

  • 主要思想:每个合数只被筛一次的算法。
  • 代码
void Euler(){
    for (int i=2;i<=n;++i){
        if (!st[i]) p[++cnt] = i;
        for (int j=1;p[j]<=n/i;++j){
            st[p[j] * i] = true;
            if (i % p[j] == 0) break;
        }
    }
}
// 为什么每个合数只会被筛一次呢?
// 因为每个合数只会被它的最小质因子筛掉
// 从小到大枚举p[j],当i%p[j]==0时, break。
// 1. 当i%p[j]==0时。说明p[j]是i的最小质因子, 那么p[j]一定也是p[j]*i的最小质因子
// 2. 当i%p[j]!=0时, 说明p[j]比i的最小质因子还小, 那么p[j]一定是p[j]*i的最小质因子
  • 时间复杂度:\(O(N)\)
posted @ 2022-05-09 23:30  跳岩  阅读(212)  评论(1)    收藏  举报