质数筛与欧拉函数
1|0第一课时
1|1复习及引入
质数判断
复杂度分析 \(O(\sqrt{n})\)
引入问题,输入n(\(1\leq n\leq10^6\))个数字(\(0\leq x \leq 10^6\)),判断每个数是不是质数?
利用已有知识,程序框架:
我们来分析下时间复杂度 \(O(n\sqrt{x})\) 。
思考,当前数据范围下是否能在1s时限内求出答案。
回答:\(10^6\times 10^3 = 10^9\) 会超时。
进一步,该怎么去更快的处理大范围内的质数?
我们提前设置一个标记数组prime[N]
,提前标记好数字的质数状态,这样就能减少重复判断。
引出质数筛法
核心思想:唯一分解定理
每个大于1的自然数,要么本身就是质数,要么可以写为2个或以上的质数的积,而且这些质因子按大小排列之后,写法仅有一种方式。
1|2埃氏筛
埃拉托斯特尼选筛法,简称埃氏筛。要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。
来理解下埃氏筛的思想
根据唯一分解定理的前半截“每个大于1的自然数,要么本身就是质数,要么可以写为2个或以上的质数的积”,那么换个角度去理解,合数一定是某个质数的倍数。
那么,当我确定一个数为质数,我自然可以将它所有的范围内的倍数(\(\ge 2\))找出来,这些倍数一定是合数。
也就是若\(p\)为质数,那么\(j\times p,(j\ge2,j\times p\le n )\) 就是合数。
以30以内的筛选为例
算法步骤:
- 设置一个标记数组vis[N],初始化为0。0-是质数 1-不是质数
- 处理特殊值 0 ,1
- 从2开始,依次将范围内的质数的倍数标记为1(非质数)
初版:
思考:第6行,为什么这样就能判断i是质数?
解答:状态数组初始化为0,循环的方向是从小到大,过程中质数的在范围内的倍数都会被筛选掉。那么到i
如果还是0,意味着质因子中不包含前面的这些质数,一个数在2~i-1
这个范围内没有因子,那么他就是质数。
优化1
根据约数的分布性,一个数n如果是合数,其中较小的约数范围一定是在\(\sqrt{n}\) 内。那么对于\(\sqrt{n}+1\)~\(n\) 范围内的合数,一定可以被\(2\)~\(\sqrt{n}\) 内的质数筛选掉。
优化2
过程中可发现很多数字被重复筛选了。
接下来就是减少重复筛选,以提高运行速度。
观察重复的数字 :
可发现质数p
与比它小的质数相乘得到的乘积,一定在之前被那么更小的质数筛过。那么筛选的时候直接从\(p^2\)开始筛选,避免重复。
时间复杂度\(O(nloglogn)\)
复杂度分析链接:https://www.cnblogs.com/dc93/p/3930362.html
1|3习题巩固
题目描述
今天是贝茜的生日,为了庆祝自己的生日,贝茜邀你来玩一个游戏。
贝茜让 N (\(1\leq N\leq 10^5\) ) 头奶牛坐成一个圈。除了$ 1 \(号与\) N \(号奶牛外,\)i$ 号奶牛与$ i−1 $号和 \(i+1\) 号奶牛相邻。$N $号奶牛与 \(1\) 号奶牛相邻。农夫约翰有一个桶,里面装满了很多纸条,每一张纸条上写了一个不一定是独一无二的 $1 $到\(10^6\) 的数字。
接着每一头奶牛 \(i\) 从桶中取出一张纸条$ A_i$ 。每头奶牛轮流走上一圈,同时拍打所有手上数字能整除在自己纸条上的数字的牛的头,然后做回到原来的位置。牛们希望你帮助他们确定,每一头奶牛走上一圈时能够拍打的牛的数量。
输入格式
第一行包含一个整数n
第二行到n+1行每行包含一个整数\(A_i\)
输出格式
共n行,每行包含一个整数,代表被拍打的牛的数量
样例输入
5
2
1
2
3
4
样例输出
2
0
2
1
3
分析
根据题意概括一下,就是给出数列a,对于第i项的\(a_i\)求出数列中有多少个是他的约数。
暴力
遍历其它元素,统计他的约数的个数即可。复杂度\(O(n^2)\)
优化
利用埃氏筛的思想,统计数组中的内容,对它的倍数做的贡献即可。
2|0第二课时
2|1欧拉筛
模拟出埃氏筛的筛选过程。
即便进行了一定的优化,但是依旧存在数字被重复筛选的问题。它的复杂度依旧不变\(O(nloglogn)\) 。
此时,若能让每个数字只被筛选一次,必然能大大地降低时间复杂度,减少运行时间,理论上的时间复杂度为\(O(n)\) 。
这种每个数字只被筛一遍的筛法叫做欧拉筛,也被称作线性筛。
那么,关键是,如何实现这一算法?
我们依旧利用唯一分解定理来实现。之前的埃氏筛,利用到了唯一分解定理的前半段,这次我们利用好它的后半截。
每个大于1的自然数,要么本身就是质数,要么可以写为2个或以上的质数的积,而且这些质因子按大小排列之后,写法仅有一种方式。
合数对应的分解因式,只要我们将这小质因子按大小排列好,那么分解式子就是唯一的。
我们要利用他的唯一性来做文章。我们只要能不重复的构造出这样的“唯一的质数序列”,那么必然不会重复筛选了。
此时我们将任意的一个数字都可看做为一个唯一的质数序列,如\(12\)可看作是序列\(2\times 2\times 3\) 。此时我们只要再找个质数,与这样的质数序列组合即可构成新的质数序列。
需要注意的是,如何防止重复?也就是怎么保证构造出来的序列的唯一性?我们新的质数组合进去之后,只要不破坏序列整体的有序性,即可实现不重复。假设,我们每次将质数是加在序列的前头,那么只需要\(P_{新质数}\leq 序列的最小质因子\) 即可保证整体有序。
例如 通过 \(2\times 2\times 3\) 进行新序列的组合的话,只能加质数2,形成新序列\(2\times 2\times 2\times 3=24\)。如果是序列\(15=3\times 5\)的话只能和2,3组合,形成新序列\(2\times 3\times5=30\)和\(3\times 3\times5=45\) 。
这样,我们在实现的时候就要在之前的基础上多一个质数表存放质数,好利用这些质数构成质数序列。
模板
时间复杂度\(O(n)\)
思考:14行操作的意义,思考为什么这么做就能不重复地筛选?
回答:质数表中的质数是从小到大的,在遍历质数表时,可看做满足\(p_j\le i的最小值因子\) ,遍历到的质数与i构成的序列就不重复。当满足整除条件时,prime[j]
就是等于i
的最小质因子,再遍历下去,就不满足质数从小到大的关系。
2|2习题巩固
哥德巴赫猜想(升级版)
问题描述
求1~N中素数的个数。
输入格式
一行一个整数N。
输出格式
一行一个数,表示素数的个数。
输入样例
10
输出样例
4
数据范围
对于40%的数据,\(1\leq N\leq 10^6\)。
对于80%的数据,\(1\leq N\leq 10^7\)。
对于100%的数据,\(1\leq N\leq 10^8\)。
分析
注意数据范围,套欧拉筛模板即可。
3|0第三课时
3|1欧拉函数
在数论中,对正整数n欧拉函数是小于或等于n的正整数中与n互质的数的数目。
例如\(\phi(1)=1,(1)\),\(\phi(8)=4,(1,3,5,7)\)。如果i是素数,则\(\phi(i)=i-1\)。
设p为质数
三个性质:
- \(\phi(p)=p-1\)
- \(i\ mod\ p = 0,\phi(i\times p)=p\times \phi(i)\)
- \(i\ mod\ p \ne 0,\phi(i\times p)=(p-1)\times \phi(i)\)
实现代码
时间复杂度\(O(n)\)
__EOF__

本文链接:https://www.cnblogs.com/wyloving/p/15982720.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)