[AcWing]868. 筛质数(C++实现)线性筛模板题

1. 题目

在这里插入图片描述

2. 读题(需要重点注意的东西)

思路:
在这里插入图片描述
线性筛法在10的6次方级数上和埃式筛法的时间差不多;在10的7次方的级数上比埃式筛法快一倍,在应用中常常使用的是线性筛法。

注:对于一个合数,它一定存在一个最小质因子

3. 解法

---------------------------------------------------解法---------------------------------------------------

#include<iostream>
using namespace std;

const int N = 1e6+10;

int primes[N],cnt;
bool st[N];

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i; // 如果i是质数,加到数表里去(从小到大存放的)
        // 每个数只会被筛一边,因此时间是线性的
        for (int j = 0; primes[j] <= n / i; j ++ ) // 从小到大枚举所有质数
        {
            /*
                注:primes[j]简写为pj
                pj小于i的所有质因子,因此pj一定是pj*i的最小质因子,将pj*i筛掉
            */
            st[primes[j] * i] = true;
            /*
                i % primes[j] == 0
                该条件成立时,pj一定是i的最小质因子,因此pj也一定是pj*i的最小质因子
                这句代码保证了每个合数只会被最小质因数筛去,将时间复杂度降到了线性
                
                如果在此时不break,则不能保证下一个primes[j+1]是primes[j+1] * i的最小质因子
            */
            if (i % primes[j] == 0) break;
        }
    }
}

int main(){
    int n;
    cin >> n;
    get_primes(n);
    cout << cnt << endl;
    return 0;
}

代码中比较难以理解的地方
本题比较难以理解的地方在这段代码

        for (int j = 0; primes[j] <= n / i; j ++ ) // 1
        {
            st[primes[j] * i] = true; // 2
            if (i % primes[j] == 0) break; // 3
        }

1、最外层的循环表示,从小到大遍历所有的质数;

2、st[primes[j] * i] = true;

作用:表示用primes[j] * i的最小质因数primes[j] 筛掉primes[j] * i这个合数。

为什么可以筛掉primes[j] * i

因为此时i % primes[j] == 0一定是未成立的,因此primes[j]一定小于i的最小质因数,因此primes[j]primes[j]*i的最小质因数

3、if (i % primes[j] == 0) break;

为什么此处要进行break?

因为此时i % primes[j] == 0成立了,primes[j]i的最小质因数。
如果此时不break,那么primes[j]会继续向后遍历,导致primes[j]不再是i的最小质因数,也不是primes[j] * i的最小质因数。

4. 可能有帮助的前置习题

5. 所用到的数据结构与算法思想

  • 线性筛法

6. 总结

线性筛法筛质数的模板题,熟记并背下来。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Cloudeeeee

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

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

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

打赏作者

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

抵扣说明:

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

余额充值