学习笔记:数学-GCD与LCM-素数筛法
筛法
埃筛
埃拉托斯特尼筛法的缩写,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-素数筛法的更多相关文章
- hdu4497 GCD and LCM ——素数分解+计数
link:http://acm.hdu.edu.cn/showproblem.php?pid=4497 如果G%L != 0,说明一定无解. 把K = G / L质数分解,G / L = p1^t1 ...
- 学习:数学----gcd及扩展gcd
gcd及扩展gcd可以用来求两个数的最大公因数,扩展gcd甚至可以用来求一次不定方程ax+by=c的解 辗转相除法与gcd 假设有两个数a与b,现在要求a与b的最大公因数,我们可以设 a=b*q+ ...
- 【Python】2.13学习笔记 数学函数和随机函数
我死了,今天看课看过头了,忘了发作业,被典明批评 而且化学作业还是瞎搞的,直接就发了 我觉得我已经提前死亡了,现在不死亡,开学也会的 函数 挺容易的,有很多语言之间重合的部分 注意 在使用某些数学函数 ...
- OI数学 简单学习笔记
基本上只是整理了一下框架,具体的学习给出了个人认为比较好的博客的链接. PART1 数论部分 最大公约数 对于正整数x,y,最大的能同时整除它们的数称为最大公约数 常用的:\(lcm(x,y)=xy\ ...
- 初等数论学习笔记 III:数论函数与筛法
初等数论学习笔记 I:同余相关. 初等数论学习笔记 II:分解质因数. 1. 数论函数 本篇笔记所有内容均与数论函数相关.因此充分了解各种数论函数的名称,定义,符号和性质是必要的. 1.1 相关定义 ...
- Canvas 数学、物理、动画学习笔记一
Canvas 第五章 数学.物理和运动学习笔记让人映像深刻的运动,需要我们不只是简单的知道如何移动对象,还需要知道怎么按用户期望看到的方式去移动它们.这些需要基于数学知识的基本算法和物理学作用.基于点 ...
- 一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记
一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记 曾经某个下午我以为我会了FWT,结果现在一丁点也想不起来了--看来"学"完新东西不经常做题不写博客,就白学了 = = 我没啥智 ...
- tensorflow学习笔记(3)前置数学知识
tensorflow学习笔记(3)前置数学知识 首先是神经元的模型 接下来是激励函数 神经网络的复杂度计算 层数:隐藏层+输出层 总参数=总的w+b 下图为2层 如下图 w为3*4+4个 b为4* ...
- 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 ...
随机推荐
- 简单聊聊Ehcache缓存
最近工作没有那么忙,有时间来写写东西.今年的系统分析师报名已经开始了,面对历年的真题,真的难以入笔,所以突然对未来充满了担忧,还是得抓紧时间学习技术. 同事推了一篇软文,看到了这个Ehcache,感觉 ...
- Vue(10)表单输入绑定v-model
v-model v-model指定可以实现表单值与属性的双向绑定.即表单元素中更改了值会自动的更新属性中的值,属性中的值更新了会自动更新表单中的值 绑定的属性和事件 v-model在内部为不同的输入元 ...
- 通过jquery创建节点以及节点属性处理
<!DOCTYPE html><html> <head> <meta http-equiv="Content-type" conte ...
- Docker减小镜像体积
导航: 这里分为几个部分. 相关转载云原生:米开朗基杨 1.Docker减小镜像体积 2.Docker镜像针对不同语言的精简策略 对于刚接触容器的人来说,他们很容易被自己制作的 Docker 镜像体积 ...
- 通过busybox制作根文件系统详细过程
我在之前的uboot通过NFS挂载ubuntu根文件系统中也有实现过根文件系统的制作,那只是在ubuntu官网已经做好的根文件基础上安装一些自己所需的软解而已.而使用busybox制作根文件系统可以自 ...
- 5、SpringBoot整合之SpringBoot整合MybatisPlus
SpringBoot整合MybatisPlus 目录(可点击直接跳转,但还是建议按照顺序观看,四部分具有一定的关联性): 实现基础的增删改查 实现自动填充功能 实现逻辑删除 实现分页 首先给出四部分完 ...
- vim编辑器使用方法(相关指令)
1.跳到文本的最后一行:按"G",即"shift+g" 2.跳到最后一行的最后一个字符 : 先重复1的操作即按"G",之后按"$& ...
- sqlite用法总结
p.p1 { margin: 0; font: 16px "Helvetica Neue"; color: rgba(0, 0, 255, 1) } p.p2 { margin: ...
- JS高阶函数的使用
1.何为高阶函数呢? JavaScript的函数其实都指向某个变量.既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数.简单来说,就是对其他 ...
- 使用Nginx和uwsgi部署Flask项目
前言 之前用Flask框架开发了一个Python的Web项目,使用Nginx和uWSGI部署起来感觉挺麻烦,过程中还因为对Flask框架的不熟悉,花了好长时间才把应用完全部署起来.下面分享部署成功 ...