ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

素数筛选法(埃氏筛 欧拉筛)

2021-11-05 12:59:15  阅读:230  来源: 互联网

标签:埃氏 int 质数 素数 筛选 1e6 primes 合数 欧拉


质数筛选法

文章目录


前言

当需要大范围内的素数时,例如 1 e 6 1e6 1e6以内时,我们就需要优秀的筛选法,如果是枚举(1 ~ n)数做朴素的判断x是否能被 2 ~ x \sqrt{x} x 中的数整除,x 从 2 ~ n, 复杂度就太高了,估算约
O ( 2 + 3 + . . . + n − 1 + n ) O(\sqrt{2} + \sqrt{3} + ... + \sqrt{n-1} + \sqrt{n}) O(2 ​+3 ​+...+n−1 ​+n ​)
势必超时,但早在几百多年前就有两位伟大的数学家发明出了埃氏筛 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)和欧拉筛 O ( n ) O(n) O(n)
两者在 1 e 6 1e6 1e6范围内效果相当,但到了 1 e 7 1e7 1e7上埃氏筛就显得乏力了。
预备知识 : 算数基本定理
简单的说一个大于1的数一定可以由若干个质数相乘得到例如: 8 = 2 ∗ 2 ∗ 2 8 = 2 * 2 * 2 8=2∗2∗2

一、埃氏筛 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)

//利用2 3 5 7 11 13...这些质数筛掉(2x, 3x, 5x, 7x, 11x, 13x, ...)剩下的便是合数
const int N = 1e6 + 10;
bool prime[N];
void prepare(int n)
{
	prime[0] = prime[1] = true;	//0和1都不是质数
    for(int i = 2; i <= n; ++i)
    {
        //prime[i] = flase 代表i是质数
        if(!prime[i])   
        {
        	//将i的倍数都标记为合数,从两倍开始
            for(int j = i << 1; j <= n; j += i)
            {
                //prime[i] = true 代表j是合数
                prime[j] = true;        
            }
        }
    }
}

总结:埃氏筛存在的缺点是一个合数可能会被多次筛选例如6会被2和3同时筛选(数据范围不超过 1 e 6 1e6 1e6影响不大),所以下面引出欧拉筛(线性筛选)

二、欧拉筛 O ( n ) O(n) O(n)

const int N = 1e6 + 10;
int cnt;
int primes[N];   //从小到大存下每个质数 
bool st[N];      //false为质数,true为合数
void get_primes(int n)
{
    for(int i = 2; i <= n; ++i)
    {
        //将质数加入质数表
        if(!st[i]) primes[cnt++] = i;
        
        //利用最小质因子来给合数打标记,必须保证每个合数都是利用最小质因子筛选一次
        for(int j = 0; primes[j] <= n / i; ++j)
        {
            st[i * primes[j]] = true;   //primes[j]为构成i * primes[j] 的最小质因子
            if(i % primes[j] == 0)
                break;
            //这段很关键,为什么要break掉,因为 i % primes[j] == 0
            //说明 primes[j]是 i 的最小质因子, 令 i = k * primes[j]
            //同时也是(i * primes[j+1]) 的最小质因子
            //如果继续执行下层循环primes[i * primes[j+1]] = true; 就说明筛选必定重复
            //因为 i * primes[j+1] = (k * primes[j]) * primes[j+1];
            //i * primes[j] 在i = (k * primes[j+1]) 时会被筛选
        }
    }
}

总结

我对素数筛选法的理解大概是这样,只是欧拉筛确实还是有点难以理解,欧拉筛这里的内层循环判断结束也很有趣,可以分三种情况。

  • primes[j] * i > n 说明范围内的素数已经被筛过,无需筛
  • i % primes[j] == 0 break 分两种
    -1. i 是合数, primes[j] 一定是小于i的最小质因数,
    -2. i 是质数, primes[j] 为当前质数表里的最后一个质数且等于i,这里保证了 j 不会大于 cnt, 不会发生质数表越界

标签:埃氏,int,质数,素数,筛选,1e6,primes,合数,欧拉
来源: https://blog.csdn.net/weixin_46211066/article/details/121159262

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有