埃氏筛

1.什么是埃氏筛

质数的倍数,绝对不是质数(比如 2 是质数,那 4、6、8 肯定都是合数)。

2. 举个栗子(找 1 到 20 的质数)

  1. 先把 1 到 20 排成一排。(1 不是质数先踢掉)。
  2. 遇到 2:2 还在队伍里,说明它是质数!接着把队伍里 2 的倍数(4, 6, 8, 10…)全踢出去。
  3. 遇到 3:3 还在队伍里,它是质数!把 3 的倍数(6, 9, 12…)全踢出去。
  4. 遇到 4:咦?4 刚才已经被 2 踢出去了,说明 4 是合数,直接跳过。
  5. 遇到 5:5 还在,它是质数!把 5 的倍数(10, 15, 20)踢出去。
  6. 一直这样扫到最后,剩下的 2, 3, 5, 7, 11, 13, 17, 19 就是所有质数。

3.如何用代码实现

定义 st 数组,st [i] 表示 i 是否为素数。prime 数组用于存储所有素数,cnt 表示当前素数的数量。

从 2 开始遍历到 n,若 st [i] 为 false,则将 i 加入 prime 数组,同时将 i 的所有倍数标记为 true。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
int primes[N],st[N];//st[i]=false代表不是素数
int n,cnt;
int main(){
    cin>>n;
    for(int i=2;i<=n;i++){
        if(st[i]==0){
            primes[cnt++]=i;
            for(int j=i+i;j<=n;j+=i) st[j]=1;
        }
    }
    cout<<cnt<<endl;
    return 0;
}

其中的j=i+i换成j=i*i可以优化时间复杂度,可以用放缩来解释,但是需要特判。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int prime[N],cnt=0;
bool st[N];//st[i]=false 表示是素数
int main(){
    int n;
    cin>>n;
    for(int i=2;i<=n;i++){
        if(st[i]) continue;
        prime[++cnt]=i;
        if((long long)(i)*i>n) continue;
        for(int j=i*i;j<=n;j=j+i){
            st[j]=true;
        }
    }
    cout<<cnt;
    return 0;
}

4.模板

模板一:标准埃氏筛

这是最经典的用法,用于快速找出所有小于等于 N的质数,并判断某个数是否为质数。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 100005; // 根据题目要求修改最大范围

vector<int> primes;           // 存储筛选出的所有质数
vector<bool> is_prime;        // is_prime[i] 表示 i 是否为质数

// 初始化标准埃氏筛
void init_sieve(int n) {
   is_prime.assign(n + 1, true);
   is_prime[0] = is_prime[1] = false; // 0 和 1 不是质数

   // 优化1:外层循环只需遍历到 sqrt(n) 即可
   for (int i = 2; i * i <= n; i++) {
       if (is_prime[i]) {
           // 优化2:内层循环直接从 i * i 开始标记,因为 i * 2, i * 3 等已经被之前的质数 2, 3 标记过了
           for (int j = i * i; j <= n; j += i) {
               is_prime[j] = false;
          }
      }
  }

   // 收集所有质数
   for (int i = 2; i <= n; i++) {
       if (is_prime[i]) {
           primes.push_back(i);
      }
  }
}

int main() {
   init_sieve(100); // 找出 100 以内的质数
   cout << "25 is prime? " << is_prime[25] << "\n"; // 输出 0 (false)
   return 0;
}

时间复杂度:o(nloglogn)

模板二:质因子预处理筛

如果你遇到的题目不光要判断质数,还需要频繁获取每个数字包含哪些质因子

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 100005;

// prime_factors[i] 存储数字 i 的所有不同质因子
vector<vector<int>> prime_factors(MAXN);

// 利用 Lambda 表达式在 main 函数之前完成全局预处理 (常数极小,力扣/打比赛常用)
int init = []() {
   for (int i = 2; i < MAXN; i++) {
       // 如果 prime_factors[i] 是空的,说明它没有被前面的数整除过,它本身就是质数
       if (prime_factors[i].empty()) {
           // 将这个质数 i 塞给它所有的倍数
           for (int j = i; j < MAXN; j += i) {
               prime_factors[j].push_back(i);
          }
      }
  }
   return 0;
}();

int main() {
   // 因为预处理在全局域已经跑完了,这里可以直接查表
   cout << "Prime factors of 12: ";
   for (int p : prime_factors[12]) {
       cout << p << " "; // 输出 2 3
  }
   cout << "\n";
   return 0;
}

时间复杂度:o(nlogn)

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇