第二十四章 数论——质数(2)(详细讲解质数的筛选原理和证明!!)

news2024/11/26 2:50:06

第二十四章 数论——质数的筛选

  • 一、朴素筛法——埃氏筛法
    • 1、问题描述
    • 2、算法思路
    • 3、代码实现
  • 二、线性筛法——欧拉筛
    • 1、朴素筛法的弊端
    • 2、欧拉筛
      • (1)算法思路
      • (2)代码实现

一、朴素筛法——埃氏筛法

1、问题描述

在这里插入图片描述

2、算法思路

我们从2开始枚举,因为2一定是质数,那么2的倍数就一定不是质数
这个是很好理解的,因为2的倍数一定是会被2整除,所以2的倍数就一定不是质数。因此我们可以直接删除掉2的倍数。
那么接着枚举,3是质数,所以3的倍数也一定不是质数。同理我们删掉所有是3的倍数的数。

按照上述的思路,如果我们某个 i i i没有被删掉的话, i i i一定是质数。为什么?

因为 i i i没有被删掉说明 i i i不是 2 2 2 i − 1 i-1 i1的倍数,也就是说 2 2 2 i − 1 i-1 i1不存在 i i i的因数。所以 i i i必定是质数。

3、代码实现

#include <iostream>
#include <algorithm>
using namespace std;
const int N= 1000010;
int primes[N], cnt;//记录所有的质数
bool st[N];//看是否被删掉
void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i + i; j <= n; j += i)
            st[j] = true;
    }
}
int main()
{
    int n;
    cin >> n;
    get_primes(n);
    cout << cnt << endl;
    return 0;
}

埃氏筛法的时间复杂度是 O ( n l o g ( l o g n ) ) O(nlog(logn)) O(nlog(logn)),可以近似看作 O ( n ) O(n) O(n)

二、线性筛法——欧拉筛

1、朴素筛法的弊端

对于刚刚的朴素筛法而言,可能会存在重复删除一个合数的情况。

比如, 6 6 6是一个合数,那么当 i = 2 i=2 i=2的时候,6是2的倍数,6会被删除一次。当 i = 3 i=3 i=3的时候,6也是3的倍数,所以6又会被删除一次。所以导致埃氏筛法的时间复杂度中有一个 l o g l o g n loglogn loglogn的系数。

而下面介绍的欧拉筛就解决了重复删除的问题,从而去掉了这个系数,使得时间复杂度变成了真正的 O ( n ) O(n) O(n)。所以欧拉筛也被成为线性筛。

2、欧拉筛

(1)算法思路

我们还以刚刚的6为例子,按照算数基本定理,6可以写成 2 ∗ 3 2*3 23两个质数相乘的形式。

为了避免重复,我们只删除具有相同最小质因数的数

刚刚的埃氏筛法是去枚举质数 i i i,然后在循环每个倍数 j j j,然后删除质数和倍数相乘组成的合数 i ∗ j i*j ij。如果还是刚刚的循环的话,我们无法保证我们枚举的那个质数 i i i就是最小的质因数,为什么呢?

因为随着 j j j的增加,我们内部循环的倍数 j j j很有可能被一个比 i i i小的质数 m m m整除,此时合数 i ∗ j i*j ij的最小质因数就不是 i i i,而是 m m m

而当 j j j继续变化, i ∗ j i*j ij的最小质因数可能又变成了另一个数。所以此时 i ∗ j i*j ij的最小质因数是摇摆不定的。

所以还按照刚刚埃氏筛法的循环设计去枚举的话,是很难优化成欧拉筛的思路的。

所以,我们需要重新设计一下循环:

刚刚的朴素筛主要问题在于内循环是倍数,这个倍数是不可控的。因此,我们颠倒一下顺序(此时的答案一定是不会漏解的),先去枚举倍数,然后再去从小到大枚举质数(把这个质数当作最小的质因数)来循环。

这个倍数就是 2 2 2 n n n的所有数字来充当的,因为我们要保证倍数和质数的乘积小于等于 n n n。所以我们的倍数是不会超过 n n n的,因此我们让这个范围的数字来充当倍数是没有问题的。

这样做有什么好处呢?

这样做就能保证我们二者相乘得到的 i ∗ j i*j ij最小质因数是一个递增的状态,是可控的。

但是我们注意的是,我们的 i i i % j ! = 0 j !=0 j=0,为什么呢?当前 i ∗ j i*j ij最小的质因数是 j j j,没错,为了方便我们标记此时的 j j j j 1 j_1 j1。那么接下来,我们会枚举比 j 1 j_1 j1大的质数 j 2 j_2 j2,目的是把 j 2 j_2 j2当成最小的质因数,但是 i ∗ j i*j ij中的 i i i的质因数已经包括了 j 1 j_1 j1,所以 i ∗ j 2 i*j_2 ij2的最小质因数也是 j 1 j_1 j1,不是 j 2 j_2 j2。也就是说我们再去枚举 > j 1 >j_1 >j1的质数已经没有意义了。

我们第二层循环的目的就是去逐步枚举越来越大的质数当作最小质因数,但是 j 1 j_1 j1存在时,后面的所有 i ∗ j n i*j_n ijn组成的合数的最小质因数都是 j 1 j_1 j1。也就是说,后续的枚举没有意义了,因此当出现 j 1 j_1 j1的时候,我们就可以终止循环了。

如果不终止的话,就会出现朴素算法的重复删除,因为我们利用质因数 j 2 j_2 j2删除了最小质因数为 j 1 j_1 j1的数字,而这些数字在枚举 j 1 j_1 j1的时候就被删掉了。

就相当于我们刚刚举得例子,6=2*3,用2已经删掉了6,但是我们又利用3去删除了一次。

很多人还会有一个担心,因为我们外层枚举的是倍数,会不会说因为删除了某个数,而让以这个数为倍数的质数漏掉了呢?

答案是不会的,因为这个数既然删掉了,那么它就是合数,合数充当倍数组成的数也一定是合数,所以不会漏解。

所以,我们如果不加跳出循环的判断语句,这个算法就会变成埃氏算法。

(2)代码实现

#include <iostream>
#include <algorithm>
using namespace std;
const int N= 1000010;
int primes[N], cnt;
bool st[N];
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[primes[j]*i]=true;
            if(i%primes[j]==0)break;
        }
    }
}

int main()
{
    int n;
    cin >> n;
    get_primes(n);
    cout << cnt << endl;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/114184.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【折腾服务器 2】妖板 Intel N5105 + i226 主板安装 群晖、直通 SATA 控制器 教程

Catch UP 前期回顾&#xff0c;我在这台使用 N5105 和 Intel 226V 2.5G 网卡的电脑上安装了 ESXi 7.0 系统。文章在博客里有&#xff0c;可以去翻翻。 Chapter 1 网络环境准备 登录 VMWare ESXi&#xff0c;点击左侧的网络。 点击 虚拟交换机 有一个 vSwitch 0 这个是默认的&a…

抽象类与接口(Java系列6)

目录 前言&#xff1a; 1.抽象类 1.1抽象类的概念及语法 1.2 抽象类的特征 1.3抽象类的特性 2.接口 2.1接口的概念及语法 2.2接口的使用及特性 2.2.1接口的使用 2.2.2接口的特性 2.3实现多个接口 2.4接口的继承 3.抽象类与接口的区别 结束语&#xff1a; 前言&…

分布式理论之分布式选举

写在前面 一个国家需要领导人制定各种国家决策&#xff0c;一个军队也需要最高统领来制定各种军事决策&#xff0c;同理&#xff0c;一个分布式集群也需要一个领导&#xff0c;来协调整个集群的事务&#xff0c;比如保证数据一致性(这也是最重要的&#xff01;)&#xff0c;分…

uni-app学习总结

本文以B站黑马教程的uni-app项目实战视频为载体&#xff0c;总结uni-app相关用法&#xff0c;如有误&#xff0c;请指出~ 一、创建项目&#xff1a; HbuilderX工具-->文件-->新建-->项目---》选择uni--app项目&#xff0c;创建。 二、项目初始化&#xff1a; 去掉一…

设计模式之结构型模式:适配器模式

前言 前面讲解完了设计模式中的创建性模式&#xff0c;本文开始讲解设计模式中的结构性模式之一&#xff1a;适配器模式。 一、适配器模式的是干什么的&#xff1f; A类想要使用B类中的某些方法&#xff0c;但是不能直接使用&#xff0c;需要一个中间类对B类进行处理后&…

C++的类型转换

目录C语言中的类型转换为什么C需要四种类型转换C强制类型转换static_castreinterpret_castconst_castdynamic_castC语言中的类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者返回值类型与接收返回值类型不…

【Linux】第七部分 Linux中系统管理

【Linux】第七部分 Linux中系统管理 文章目录【Linux】第七部分 Linux中系统管理7. Linux中系统管理7.1 进程和服务7.2 service 服务管理systemctl 基本语法systemctl设置后台服务的自启动配置关机重启命令总结7. Linux中系统管理 7.1 进程和服务 一个正在执行的程序或命令&a…

2023年快到了,就简单用python写个对联吧

人生苦短 我用python 我知道现在离过年还早~ 但是早点准备早点轻松~ Python写对联挺火的&#xff0c;但是代码又不是人人都用&#xff0c;那就直接写个界面打包一下呗~ 主要实现只要运行后输入上联下联、横批&#xff0c;然后自动生成春联保存在代码文件夹&#xff0c;如果…

梦想SkyPython IDLE入门

IDLE是Python软件包自带的一个集成开发环境&#xff0c;初学者可以利用它方便地创建、运行、测试和调试Python程序。 一、IDLE的安装 实际上&#xff0c;IDLE是跟Python一起安装的&#xff0c;不过要确保安装时选中了“Tcl/Tk”组件&#xff0c;准确地说&#xff0c;应该是不要…

六、应用层(一)网络应用模型

目录 1.1 客户/服务器模型 1.2 P2P模型 应用层是计算机网络体系结构的最顶层&#xff0c;是设计和建立计算机网络的最终目的&#xff0c;也是计算机网络中发展最快的部分。 早期基于文本的应用&#xff08;电子邮件、远程登陆、文件传输、新闻组&#xff09;20世纪90年代将…

node.js+uni计算机毕设项目基于微信小程序的培训机构管理系统小程序(程序+小程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等…

六、应用层(二)域名系统(DNS)

目录 2.1层次域名空间 2.2域名服务器 2.3域名解析过程 域名系统&#xff08;Domain Name System,DNS&#xff09;是因特网使用的命名系统&#xff0c;用来把便于人们记忆的具有特定含义的主机名转换为便于机器处理的IP地址。 多台主机可以映射到同一个域名上&#xff08;如负…

智慧工地车辆冲洗系统 工地渣土车未冲洗自动抓拍 yolo

智慧工地车辆冲洗系统 工地渣土车未冲洗自动抓拍 通过Python基于YOLOv7深度学习网络对现场画面实时监测分析。当识别到现场车辆冲洗不干净或者没有冲洗&#xff0c;系统就立即抓拍。与C / C等语言相比&#xff0c;Python速度较慢。也就是说&#xff0c;Python可以使用C / C轻松…

SpringCloud图文详解 | 两种注册中心远程调用负载均衡服务网关... | 系统性学习 | 无知的我费曼笔记

无知的我正在复盘SpringCloud&#xff0c;顺便上传笔记。 下图是我总结的 SpringCloud 知识的初级思维导图&#xff0c;后续会不断补充 文章目录微服务技术演变单体架构分布式架构微服务 - 特点微服务实现 - 技术对比微服务技术 - 实际应用SpringCloud知识点总结服务拆分和…

SSM框架学习记录-SpringMVC_day02

1.SSM整合 代码参考Springmvc_08_ssm 流程分析 添加依赖&#xff1a;pom.xml编写配置类&#xff1a; Spring的配置类SpringConfig.javaSpringMVC的配置类SpringMvcConfig.javaWeb项目的入口配置类ServletConfig.javaMyBatis的配置类MyBatisConfig.java第三方数据源的配置类Jdbc…

uniapp动态切换显示不同内容组件

需求描述 通过点击注册或是登录按钮切换不同的组件.默认显示登陆界面,登录字样加粗显示,登录页面显示手机号密码登录.点击注册切换到注册页面,注册字样加粗显示,页面显示手机号和验证码以及注册按钮.对应页面显示如下: 实现代码: <template><view class"conte…

pytorch实战(五)——时间序列多步预测的五种方法介绍

当需要根据已有的时间序列数据&#xff0c;预测未来多个时刻的状态时&#xff0c;被称之为时间序列多步预测。 时间序列多步预测有五种策略&#xff0c;分别为&#xff1a; 1、直接多步预测&#xff08;Direct Multi-step Forecast&#xff09; 2、递归多步预测&#xff08;Rec…

Redis5.0+——主从复制

说明 主机数据更新后根据配置和策略&#xff0c;自动同步到备机的master/slave机制&#xff0c;Master以写为主&#xff0c;Slave以读为主&#xff08;一主一从&#xff0c;一主多从&#xff09; 能实现目的 读写分离&#xff0c;性能拓展容灾区快速恢复&#xff08;当一个从…

【软件测试】资深测试的总结,接口测试中的最常见的几个错误......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 为了彻底进行API接口…

入门力扣自学笔记221 C++ (题目编号:1739)

1739. 放置盒子 题目&#xff1a; 有一个立方体房间&#xff0c;其长度、宽度和高度都等于 n 个单位。请你在房间里放置 n 个盒子&#xff0c;每个盒子都是一个单位边长的立方体。放置规则如下&#xff1a; 你可以把盒子放在地板上的任何地方。 如果盒子 x 需要放置在盒子 y…