筛法

埃筛

埃拉托斯特尼筛法的缩写,EraSieve (这个英文其实是为了方便做函数名不要再写shake了)

它的核心思想其实是当确认了一个数是质数以后,把它的所有倍数打上标记说这玩意不是质数。那现在的问题就只剩下怎么确定一个数是不是质数了。

原理

我们先这样想,如果一个数 \(n\)​​ 是合数,那么一定可以表示为 \(a*b\)​​ , 其中 \(a、b\)​​ 都不能等于 \(1\)​​ 和 \(n\)​​ ,那这样的话 \(a、b\)​​ 都一定会是小于 \(n\)​​ 的,也就是说如果我们在\(2\sim n\)​​ 遍历的话,只要 \(n\)​​​ 是合数,那么它一定会在遍历到它之前被筛掉(相当于是它是某个小于它的数的倍数)。那么我们只需要从 \(2\)​​​ 开始遍历,记录每一个数有没有被筛掉,如果在遍历的它的时候没有被筛过,那么它就一定是质数(相当于是它不能表示为某个小于它的数的倍数,大于它的数就更不可能)。

代码
int not_pri[MX]={0};//not_pri[i]表示i这个数是否为质数,质数为0,非质数为1
void EraSieve(int range){//筛出所有小于range的质数
not_pri[1]=0;//如果想让not_pri表示非合数,那么这里需要让not_pri[1]=1
for(int i=2;i<=range;i++){
if(not_pri[i]==0){//如果i不是质数,那么它就没有必要再翻倍,因为它的倍数必然可以表示为它的某个质因数的倍数,所以必定已经被筛过了
for(int j=2;i*j<=range;j++){
not_pri[i*j]=1;//筛除倍数
}
}
}
}
复杂度分析

时间复杂度:\(O(n\log\log n)\)​ (范围*质数个数)

欧拉筛

也叫线性筛,EulerSieve (还是方便的函数名)

欧拉筛其实是针对埃筛的超级优化,它们的大致想法是一样的,都是把质数的倍数打上标记来筛掉合数,埃筛的花时间主要是在筛掉倍数,我们继续想一想埃筛的遍历方式里面是不是有针对合数的倍数的剪枝,但是我们来看这样一个例子:

当\(i=2\)的时候,筛掉了\(\ \ 4,\ \ 6,\ \ 8,10,12,14,16,18\dots\)

当\(i=3\)​的时候,筛掉了\(\ \ 6,\ \ 9,12,15,18,21,24,27\dots\)​​

你会发现,虽然我们只筛掉质数的倍数,但是在上面那个例子里,所有 \(6\)​ 的倍数都会被筛两遍,那如果一个数有多个质因子呢?重复筛的次数是不是更多了?是不是就造成了更多的无用循环?那么这个只根据是不是质数进行剪枝是不是可以更加精准呢?所以欧拉筛就诞生了。

让每一个数只被它最小的质因数筛到,就是欧拉筛改进后的剪枝方法,也是欧拉筛的核心思想。那具体要怎么实现呢?

原理

我们拿 \(12\) 做一个例子,按照我们埃筛的方式来,会这样反复的筛掉 \(12\) : \(2*6=3*4\) 。想办法只用\(2*6\)来筛掉 \(12\) 就可以了,我们可以发现一个数除以它最小的质因数得到的数一定是它最大的因数(\(2*6\)),而其他的表示方法一定可以分解成更小的质因数相乘的形式(\(3*4=3*2*2=2*6\)),也就是说如果一个数 \(n\) 除以一个质因数 \(x\) 得到的数 \(y\) 是一个比这个质数 \(x\) 更小的质数的倍数,那么这个质数 \(x\) 就一定不是最小的质数,自然也就不用这个质数来筛了。 结合 \(12\) 的例子来理解一下这句话:\(n=12,x=3\) 得 \(y=12 /3=4\) ,因为\(\ 4=2*2\ , \ 2<3\),所以 \(3\)​ 不是最小质数。

其实这样麻烦的判别方法对于单个单个的数来说肯定不是最优的(直接挨个枚举\(2\sim\sqrt{n}\)​​看是不是整除岂不是更简单),之所以要用这样的一个性质,是因为我们需要筛啊,筛就需要枚举倍数,所以需要找一个通过倍数的关系来确定是不是最小质因数的性质。

接着看,可以发现只要是任何一个大于 \(2\) 的质数 \(x\) 来乘上 \(4\) 得到的准备筛掉的数一定可以写成 \(2*2x\)的形式,就是说它的最小质因数肯定就不是 \(x\) 了,而是 \(2\) 了,那么就没有必要继续将之后的质数都没有必要筛掉他们的 \(4\) 倍,因为他们的 \(4\) 倍数肯定可以被 \(2\) 筛掉。更一般化的形式就是,如果正在筛掉一个质数\(x\)的\(y\)倍,而这个 \(y\) 能被一个比 \(x\) 小的质数 \(z\) 整除,所以 \(x*y\) 一定可以表示为 \(z*k\) ,而 \(z\) 是比 \(x\) 小的,回到欧拉筛的核心思想:“每一个数只被它最小的质因数筛到”,所以所有大于 \(x\) 的质数都不用筛 \(y\) 倍了,因为一定可以在筛去 \(z\) 的 \(k\) 倍时筛去。(这里可以求出来\(\displaystyle k=\frac{x*y}{z}\));

为了用上这个那我们再改一下筛的方法,埃筛的方法是通过枚举一次性把这个质数的所有倍数全部标记完,而欧拉筛是先枚举质数的乘数,每一次标记上目前所有已知质数的某个确定的倍数(比如说都筛去目前已所有质数的\(3\)倍,下一次筛去所有已知质数的 \(4\) 倍,每筛一次单个质数最多只会多一倍),这样就可以利用到上两段发现的性质来进行优化了。而这里的枚举倍数再仔细一看,其实可以利用埃筛里枚举的 \(i\) ,\(i\)​ 在这里有了两个意义:①当前需要判断是不是质数的数;②所有质数筛去的倍数

代码
int pri[MX]={0};// pri[i]储存质数表,其中pri[0]表示这个质数表里有多少个数
int not_pri[MX]={0};//同埃筛里的not_pri[]
void EularSieve(int range){
for(int i=2;i<range;i++){
//i的第一个意义:判断i是不是质数,判断理由和埃筛一模一样
if(not_pri[i]==0)
pri[++pri[0]]=i;
//i的第二个意义:筛去 目前所有已知质数*i 得到的合数
for(int j=1;j<=pri[0];j++){//枚举当前已知质数
if(pri[j]*i>range)break;//超出判断范围
not_pri[pri[j]*i]=1;
//重点!
if(i%pri[j]==0)break;
//用上面一般化的形式来表述的话,x=pri[j],y=i,这里由于pri是递增的,所以就相当于是判断y能不能被更小的质因数整除
//如果i%pri[i]为0了,那么就找到了一个比x小的质数z,那么之后的倍数的最小的质因数就不再是x而是z了,所以不用接着筛了
}
}
}
复杂度分析

时间复杂度:\(O(n)\)​​​​​ (每个数只被筛去一次)

学习笔记:数学-GCD与LCM-素数筛法的更多相关文章

  1. hdu4497 GCD and LCM ——素数分解+计数

    link:http://acm.hdu.edu.cn/showproblem.php?pid=4497 如果G%L != 0,说明一定无解. 把K = G / L质数分解,G / L = p1^t1 ...

  2. 学习:数学----gcd及扩展gcd

    gcd及扩展gcd可以用来求两个数的最大公因数,扩展gcd甚至可以用来求一次不定方程ax+by=c的解   辗转相除法与gcd 假设有两个数a与b,现在要求a与b的最大公因数,我们可以设 a=b*q+ ...

  3. 【Python】2.13学习笔记 数学函数和随机函数

    我死了,今天看课看过头了,忘了发作业,被典明批评 而且化学作业还是瞎搞的,直接就发了 我觉得我已经提前死亡了,现在不死亡,开学也会的 函数 挺容易的,有很多语言之间重合的部分 注意 在使用某些数学函数 ...

  4. OI数学 简单学习笔记

    基本上只是整理了一下框架,具体的学习给出了个人认为比较好的博客的链接. PART1 数论部分 最大公约数 对于正整数x,y,最大的能同时整除它们的数称为最大公约数 常用的:\(lcm(x,y)=xy\ ...

  5. 初等数论学习笔记 III:数论函数与筛法

    初等数论学习笔记 I:同余相关. 初等数论学习笔记 II:分解质因数. 1. 数论函数 本篇笔记所有内容均与数论函数相关.因此充分了解各种数论函数的名称,定义,符号和性质是必要的. 1.1 相关定义 ...

  6. Canvas 数学、物理、动画学习笔记一

    Canvas 第五章 数学.物理和运动学习笔记让人映像深刻的运动,需要我们不只是简单的知道如何移动对象,还需要知道怎么按用户期望看到的方式去移动它们.这些需要基于数学知识的基本算法和物理学作用.基于点 ...

  7. 一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记

    一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记 曾经某个下午我以为我会了FWT,结果现在一丁点也想不起来了--看来"学"完新东西不经常做题不写博客,就白学了 = = 我没啥智 ...

  8. tensorflow学习笔记(3)前置数学知识

    tensorflow学习笔记(3)前置数学知识 首先是神经元的模型 接下来是激励函数 神经网络的复杂度计算 层数:隐藏层+输出层 总参数=总的w+b 下图为2层 如下图 w为3*4+4个   b为4* ...

  9. hdu 4497 GCD and LCM 数学

    GCD and LCM Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4 ...

随机推荐

  1. MATLAB导入txt和excel文件技巧汇总:批量导入、单个导入

    在使用MATLAB的时候,想必各位一定会遇到导入数据的问题.如果需要导入的数据其数据量巨大的话,那么在MATLAB编辑器中将这些数据复制粘贴进来,显然会在编辑器中占据巨大的篇幅,这是不明智的. 一般来 ...

  2. 并发王者课-铂金8:峡谷幽会-看CyclicBarrier如何跨越重峦叠嶂

    欢迎来到<并发王者课>,本文是该系列文章中的第21篇,铂金中的第8篇. 在上一篇文章中,我们介绍了CountDownLatch的用法.在协调多线程的开始和结束时,CountDownLatc ...

  3. 如何优雅地实现浏览器兼容与CSS规则回退

    读完了<Visual Studio Code权威指南>,前端方面书籍不能停,于是捡起「CSS一姐」 Lea Verou 的<CSS魔法>. 我们没法控制用户使用新版本还是老版本 ...

  4. 11、linux的目录结构

    11.1.查看磁盘的id: blkid 11.2.linux目录类似一个倒挂的树: / 是所有目录的顶点,目录磁盘和分区是没有关联的,因此/下不同的目录会对应不同的磁盘的不同的分区: linux中硬盘 ...

  5. 12、windows定时备份数据库

    12.1.删除指定目录中的内容: del /Q E:\DATABAK\* copy 1.txt bak\a.txt 12.2.可用的备份计划: 1.脚本: BakScripts @echo off R ...

  6. angular组件间的通信(父子、不同组件的数据、方法的传递和调用)

    angular组件间的通信(父子.不同组件的数据.方法的传递和调用) 一.不同组件的传值(使用服务解决) 1.创建服务组件 不同组件相互传递,使用服务组件,比较方便,简单,容易.先将公共组件写在服务的 ...

  7. js--你需要知道的字符串使用方法(含es6及之后)

    前言 字符串作为 JavScript 的基本数据类型,在开发以及面试过程中作为程序员对基础掌握情况的重要考点,本文来总结一下字符串的相关属性以及用法.包含了ES6中的一些新语法特性. 正文 1.字符串 ...

  8. Redis:Java链接redis单节点千万级别数据 写入,读取 性能测试

    本文是对Redis 单节点,针对不同的数据类型,做插入行测试. 数据总条数为:10058624 环境说明:             Redis 未做任何优化, 单节点    (服务器上, 内存64G) ...

  9. Docker:docker国内镜像加速

    创建或修改 /etc/docker/daemon.json 文件,修改为如下形式 { "registry-mirrors": [ "https://registry.do ...

  10. python之struct详解

    python之struct详解 2018-05-23 18:20:29 醉小义 阅读数 20115更多 分类专栏: python   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议 ...