埃氏筛法与欧拉筛的原理

关于合数一定有质因子的证明

另外注明,素数即质数

	一个合数n之所以为合数,就是因为除1和本身之外,还至少有一个不等于n的素因子p。
    
	所以,一个合数n,如果存在大于1的正整数m和素数p,使n=m*p,则p为n的素因子,若m为合数,
则重复以上步骤求其余的素因子,直到n分解为素因子的乘积。

	例如256=2*2*2*2*2*2*2*2,510510=2*3*5*7*11*13*17.

也正是因为所有的合数一定有质因子,所以埃氏筛法和欧拉筛才是正确的

埃氏筛法的原理
从2开始,当我们遍历到一个素数时,把所有该素数的倍数(自然是合数)都筛选出来,进行标记
欧拉筛的原理

注:本段有参考某位大佬的文章

传送门

埃氏筛法的缺陷 :对于一个合数,有可能被筛多次。例如 30 = 2 * 15 = 3 * 10 = 5*6……那么如何确保
每个合数只被筛选一次呢?我们只要用它的最小质因子来筛选即可,这便是欧拉筛法。

所以欧拉筛是在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100;
int prime[maxn];
int visit[maxn];
int main(){
	int cnt=0;
    memset(visit,0,sizeof(visit));
    memset(prime, 0,sizeof(prime));
    for (int i = 2;i <= maxn; i++) {//打表测试一下 
        cout<<"当 i = "<<i<<"时"<<endl;
        if (!visit[i]) 
            prime[cnt++] = i;      //纪录素数, 这个prime[0] 相当于 cnt,用来计数
        for (int j = 0; j <cnt&& i*prime[j] <= maxn; j++) {
            cout<<"  j = "<<j<<" prime["<<j<<"]"<<" = "<<prime[j]<<" i*prime[j] = "<<i*prime[j]<<endl;
            visit[i*prime[j]] = 1;
/*
解释一:
prime[j]是当前已经确定的素数,而i*prime[j]计算的该素数的倍数 
此前有一点疑惑, i是外层循环的控制变量,有可能轮到这个素数的时候,i已经>2、3、4、5。。。了
就没办法计算这个素数的 2、3、4、5。。。倍了,但是其实是这样的,如果该素数前有素数
那么其实这两个素数的倍数已经被标记为合数了, 作为(比prime[j]小的素数)的倍数被标记了 
解释二: 
我们之前做埃氏筛法的优化时就已经知道了,循环标记时j的下标应该从i*i开始,原因见《计算机考研机试指南 》P96 
而在这里,我们得到一个新的素数的时候,prime[j]是通过i赋值给它得到的,那么其实i*prime[j]的初始值就相当于i*i 
也因此i是不会小于prime[j]的,也即i>=prime[j] 永真 
i如果是素数,那么i=prime[j]的最大值
i如果是合数,那么i>prime[j]的最大值 
*/
            if (i % prime[j] == 0) break;
/*
j是从小到大的, 那么prime[j]也是从小到大的,prime[j]里面存的都是素数,那么i对prime[j]求余能除尽,说明prime[j]是i的质因子 
那么i对prime[j]求余,遇到的第一个能除尽的数就是i的最小质因子
*/
        }
    }
}

《计算机考研机试指南 》P96 alt

以下是与本期主题无关的一个小知识
	在if(表达式){语句} 条件语句里,如果表达式值为真的话,刚执行花括号里的语句;
	若表达式为假,刚不执行。
    1. if(!i)
    	表达式为(false)假,等价于i==0;
    2. if(i)
    	表达式为(true)真,等价于i!=0。(可假设i=1)
    可以简单记为"假零 真一"(贾玲)
菜鸟成长记 文章被收录于专栏

根据自己的学习历程,记录该过程中的各种困惑以及解决困惑的方法

全部评论

相关推荐

12-27 22:49
门头沟学院 Java
点赞 评论 收藏
分享
Tom哥981:让我来压力你!!!: 这份简历看着“技术词堆得满”,实则是“虚胖没干货”,槽点一抓一大把: 1. **项目描述是“技术名词报菜名”,没半分自己的实际价值** 不管是IntelliDoc还是人人探店,全是堆Redis、Elasticsearch、RAG这些时髦词,但你到底干了啥?“基于Redis Bitmap管理分片”是你写了核心逻辑还是只调用了API?“QPS提升至1500”是你独立压测优化的,还是团队成果你蹭着写?全程没“我负责XX模块”“解决了XX具体问题”,纯把技术文档里的术语扒下来凑字数,看着像“知道名词但没实际动手”的实习生抄的。 2. **短项目塞满超纲技术点,可信度直接***** IntelliDoc就干了5个月,又是RAG又是大模型流式响应又是RBAC权限,这堆活儿正经团队分工干都得小半年,你一个后端开发5个月能吃透这么多?明显是把能想到的技术全往里面塞,生怕别人知道你实际只做了个文件上传——这种“技术堆砌式造假”,面试官一眼就能看出水分。 3. **技能栏是“模糊词混子集合”,没半点硬核度** “熟悉HashMap底层”“了解JVM内存模型”——“熟悉”是能手写扩容逻辑?“了解”是能排查GC问题?全是模棱两可的词,既没对应项目里的实践,也没体现深度,等于白写;项目里用了Elasticsearch的KNN检索,技能栏里提都没提具体掌握程度,明显是“用过但不懂”的硬凑。 4. **教育背景和自我评价全是“无效信息垃圾”** GPA前10%这么好的牌,只列“Java程序设计”这种基础课,分布式、微服务这些后端核心课提都不提,白瞎了专业优势;自我评价那堆“积极认真、细心负责”,是从招聘网站抄的模板吧?没有任何和项目挂钩的具体事例,比如“解决过XX bug”“优化过XX性能”,纯废话,看完等于没看。 总结:这简历是“技术名词缝合怪+自我感动式凑数”,看着像“背了后端技术栈名词的应届生”,实则没干货、没重点、没可信度——面试官扫30秒就会丢一边,因为连“你能干嘛”都没说清楚。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务