欧拉筛选法求素数 (例:洛谷P3912 素数个数)

前言

之前笔试写到了一个素数判断,但是超时了(尴尬,当时知道用欧拉筛,但是忘记怎么写了),于是决定写一篇博客加深下印象 。
绝对不是水博客

普通筛素数

  • 思路:先筛掉除了2之外2的倍数,然后i从3开始循环,每次+2,结束条件i*i<n,剩下活着的数就是素数啦
  • 代码
//判断一个数是不是素数
//当然可以用数组来存状态
bool f(int n){
    if(n == 2) return true;
    if(n%2 == 0) return false;
    for(int i = 3; i*i <= n; i+=2){
        if(n%i == 0) return false;
    }
    return true;
}

那如果我们用数组的下标来存状态判断是不是素数呢?
我们将素数从2开始挨个乘积的下标标记为非素数

int t[10000]={0};
void f1(int n){
    t[0] = t[1] = 1;
    for(int i = 2; i*i < n && !t[i]; i++){
        if(t[i]) continue;
        for(int j = 2; j <= i; j++){
            t[i*j] = 1;//标记为非素数
        }
    }
}

这样t[i]=0的 i 就是素数。但是这样很容易发现一个缺点,就是会重复晒出一些数。比如12会被26、34、43、62重复筛选,这个时候就轮到欧拉筛选出场了,时间复杂度O(n)。

欧拉筛选素数

  • 参考例题:洛谷P3912
  • 题目传送门:P3912素数个数
  • 题目大概意思:
    求 1,2,⋯,N 中素数的个数。

对于 100% 的数据,1<n<1e8

思路:
欧拉筛选法求素数,通过质数来筛掉他的倍数
关键:每个数都被他的最小质因数筛掉
这样就可以避免重复筛选
5800000//10^8的范围大概有5700000多个素数
要用bool类型的数组判断,不然会超内存

#include <iostream>
#include<bits/stdc++.h>
#define ll long long

using namespace std;

/*
欧拉筛选法求素数
通过质数来筛掉他的倍数
关键:每个数都被他的最小质因数筛掉
5800000//10^8的范围大概有5700000多个素数
*/
const int MaxN = 100000000+5;
bool dp[MaxN];//判断下标是否为素数
//用int数组会超内存
int prim[5800000] = {0};//记录素数的值
ll cnt = 0;

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

int main()
{
    int n;
    cin >> n;
    dp[0] = dp[1] = 1;//0表示素数
    for(int i = 2; i <= n; i++){
        if(!dp[i]){
            //i是素数
            prim[cnt++] = i;
        }
        //用素数筛掉非素数
        for(int j = 0; j<cnt&&i*prim[j]<=n; j++){
            dp[i*prim[j]] = 1;
            if(i%prim[j] == 0){
                //这里很重要
                //保证每一个数都是被它的最小质因数筛掉
                //比如prim里面放2 3 5 7 11,此时i为12
                // 2, 2; 2 3, 3*2 3*3;
                //此时i=4,只筛掉2*4,不会筛掉4*3
                //因为4*3=12要被6*2筛掉,保证被最小质因数筛掉
                //这样避免重复筛
                break;
            }
        }
    }
    cout << cnt << endl;
    return 0;
}

总结

用最小质因数来筛选掉非素数,比如12只能被2 * 6筛,而不是被3 * 4筛掉。这样就可以避免重复筛除。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值