Acwing 质数

news2024/11/17 6:47:11

1.试除法判定质数

首先回顾一下什么是质数?

  • 对所有大于1的自然数,如果这个数的约数只包含1和它本身,则这个数被称为质数或者素数

试除法:对于一个数n,从2枚举到n-1,若有数能够整除n,则说明除了1和n本身,n还有其它约数,则n不是质数;否则,n是质数;

  • 优化:由于一个数的约数都是成对出现的。比如12的一组约数是3,4,另一组约数是2,6。则我们只需要枚举较小的那一个约数即可。我们用d|n来表示d整除n,只要满足d|n,则一定有{n/d}|n,比如3∣12,则{12/3} | 12,因为约数总是成对出现的,我们只需要枚举小的那部分数即可,令d ≤ n/d,即,d ≤ sqrt{n},因此对于n,只枚举2到sqrt{n}即可。
  • 注意:for循环的结束条件,推荐写成i <= n / i。有的人可能会写成i <= sqrt(n),这样每次循环都会执行一次sqrt函数,而这个函数是有一定时间复杂度的。而有的人可能会写成i * i <= n,这样当i很大的时候(比如i比较接近int的最大值时),i * i可能会溢出,从而导致结果错误。

Acwing 866.试除法判定质数
在这里插入图片描述
具体实现代码(详解版):

#include <iostream>  
using namespace std;

//试除法:用于判断传入的整数 x 是否为素数
bool is_prime(int x){
    // 如果 x 小于 2,则不是素数,返回 false
    if(x < 2) return false;
    
    // 从 2 开始迭代,直到 i * i <= x (相当于 i <= sqrt(x)),检查是否有因数
    for(int i = 2; i <= x / i; i++){
        // 如果 x 能被 i 整除,说明 x 不是素数,返回 false
        if(x % i == 0)
            return false;
    }
    
    // 如果没有找到任何因数,返回 true,表示 x 是素数
    return true;
}

int main(){
    int n, x;  
    cin >> n;  
    while(n --){  
        cin >> x;  
        // 如果 x 是素数,输出 "Yes",否则输出 "No"
        if(is_prime(x)) puts("Yes");
        else puts("No");
    }
    
    return 0; 
}

2.质因数分解:试除法

对于一个整数 N 总能写成如下形式:
N = P 1 α 1 × P 2 α 2 × P 3 α 3 ⋯ × P n α n N=P_{1} ^{α_1} \times P_{2} ^{α_2} \times P_{3} ^{α_3} \dots \times P_{n} ^{α_n} N=P1α1×P2α2×P3α3×Pnαn
其中Pi都是质数,αi为大于0的正整数,即一个整数可以表示为多个不同质数的次方的乘积

  • 对于一个数求质因数的过程:从2到n,枚举所有数,依次判断是否能够整除n即可。朴素法,时间复杂度O(n))。;
  • 优化:n中只包含一个大于sqrt{n}的质因子,很好证明,如果中包含两个大于sqrt{n}的质因子,那么乘起来就大于n了。因此,在枚举的时候可以先把2到sqrt{n}的质因子枚举出来,如果最后处理完n > 1,那么这个数就是那个大于\sqrt{n}的质因子,单独处理一下就可以。时间复杂度降为O(sqrt(n))

求质因数分解,为什么枚举所有数,而不是枚举所有质数,万一枚举到合数怎么办?解释:枚举数时,对于每个能整除 n 的数 i先把这个数除干净了(就是把这个质数的次方剔除了,表现在上式中就是逐步去除Pi^αi),再继续枚举后面的数,这样能保证,后续再遇到能整除的数,一定是质数而不是合数。

例如:求180的质因数分解

  1. i = 2 n = 180 / 2 = 90 / 2 = 45
  2. i = 3 n = 45 / 3 = 15 / 3 = 5
  3. i = 4 当i是合数时,i 一定不能整除 n 。如果 4 能整除 n 那么 2 一定还能整除 n,就是在 i = 2的时候没有除干净,而我们对于每个除数都是除干净的,因此产生矛盾。
  4. i = 5 n = 5 / 5 = 1

Acwing 867.分解质因数
在这里插入图片描述
具体实现代码(详解版):

#include <iostream>  

using namespace std;

// 使用试除法分解质因数
void divide(int x){
    // 从 2 开始迭代,直到 i * i <= x (相当于 i <= sqrt(x)),试图找到因数
    for(int i = 2 ; i <= x / i ; i ++){
        // 如果 x 能被 i 整除,则 i 是 x 的一个质因数
        if(x % i == 0){
            int s = 0;  // 计数 i 的出现次数
            // 用 while 循环找出 i 作为因子的次数,直到 x 不能被 i 整除
            while(x % i == 0) x /= i, s ++;
            cout << i << ' ' << s << endl;
        }
    }
    // 如果 x 最后还大于 1,说明剩下的 x 是一个大于 sqrt(x) 的质数
    if(x > 1) cout << x << ' ' << 1 << endl; 
    cout << endl;  
}

int main(){
    int n, x;  
    cin >> n;  
    while(n --){  
        cin >> x;  
        divide(x); 
    }
    
    return 0;  
}

3.筛质数–朴素法

将2到n全部数放在一个集合中,遍历2到n,每次删除当前遍历的数在集合中的倍数。最后集合中剩下的数就是质数。

解释:如果一个数p没有被删掉,那么说明在2到p-1之间的所有数,p都不是其倍数,即2到p-1之间,不存在p的约数。故p一定是质数。

时间复杂度:
n 2 + n 3 + ⋯ + n n = n ln ⁡ n < n log ⁡ 2 n \frac{n}{2} + \frac{n}{3} + \dots +\frac{n}{n} = n\ln_{}{n} < n\log_{2}{n} 2n+3n++nn=nlnn<nlog2n
故,朴素思路筛选质数的时间复杂度大约为O(nlogn)

Acwing 868.筛质数
在这里插入图片描述
具体实现代码(详解版):

#include <iostream>
using namespace std;

const int N = 1000010; 
int primes[N], cnt;     // primes 数组存储所有找到的素数,cnt 计数素数的个数
bool st[N];             // st 数组标记数字是否被筛掉,false 表示未筛掉,true 表示已筛掉

// 朴素筛法,用于筛选出小于等于 n 的所有素数
void get_prime(int n) {
    // 从 2 开始遍历到 n,逐个检查数字是否是素数
    for (int i = 2; i <= n; i++) {
        // 如果 st[i] 为 false,说明 i 没有被筛掉,因此 i 是素数
        if (!st[i]) primes[cnt++] = i;
        
        // 将所有 i 的倍数标记为 true,表示这些数不是素数
        for (int j = i + i; j <= n; j += i) {
            st[j] = true;
        }
    }
}

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

4.筛质数–埃氏筛法

在上面朴素筛法的基础上,

其实不需要把全部数的倍数删掉,而只需要删除质数的倍数即可

对于一个数p,判断其是否是质数,其实不需要把2到p-1全部数的倍数删一遍,只要删掉2到p-1之间的质数的倍数即可。因为,若p不是个质数,则其在2到p-1之间,一定有质因数,只需要删除其质因数的倍数,则p就能够被删掉。埃氏筛法筛选质数的时间复杂度大约为O{nlog(logn)}

具体实现代码(详解版):

#include <iostream>  
using namespace std;

const int N = 1000010; 
int primes[N], cnt;     // primes 数组存储所有素数,cnt 记录素数的个数
bool st[N];             // st 数组用于标记每个数是否被筛掉,false 表示未筛掉

// 埃拉托斯特尼筛法,找出小于等于 n 的所有素数
void get_prime(int n) {
    // 从 2 开始遍历,检查每个数是否是素数
    for (int i = 2; i <= n; i++) {
        // 如果 i 没有被筛掉,则 i 是一个素数
        if (!st[i]) {
            primes[cnt++] = i;  // 将素数存储到 primes 数组中,并增加素数个数计数
            // 将 i 的所有倍数标记为非素数,从 i * 2 开始,每次增加 i
            for (int j = i + i; j <= n; j += i)
                st[j] = true;  // 标记 i 的倍数为 true,表示它们不是素数
        }
    }
}

int main() {
    int n;
    cin >> n;  // 输入一个整数 n,表示筛选范围为 2 到 n
    get_prime(n);  // 调用 get_prime 函数进行素数筛选
    cout << cnt << endl;  // 输出素数的个数
    return 0;
}

5.筛质数–线性筛法

大体思路和埃氏筛法一样,将合数用他的某个因数筛掉,其性能要优于埃氏筛法(在 1 0 6 10^{6} 106下两个算法差不多,在10^7下线性筛法大概快一倍)核心思路是:对于某一个合数n,其只会被自己的最小质因子给筛掉,从而避免了重复标记

设置一个primes数组,存储质数(以下叙述用pj来表示primes[j]),从2到n进行循环遍历,用数组st[]标记是否为质数。每次循环都对当前质数数组进行遍历,用其最小质因子筛除合数

  • i % pj == 0时:pj 一定是 i 的最小质因子,因为我们是从小到大枚举质数的,首先遇到的满足i % p j == 0的,pj 一定是 i 的最小质因子并且pj 一定是pj * i的最小质因子。比如,15 = 3 *5,15的最小质因子是3,则15的倍数中最小的数,其最小质因子同样是3的,15乘以最小质因子3,即45;
  • i % pj != 0时:pj 一定不是 i 的质因子,并且由于是从小到大枚举质数的,那么 pj 一定小于 i 的全部质因子。那么 pj 就一定是 pj * i 的最小质因子

具体实现代码(详解版):

#include <iostream>
using namespace std;

const int N = 1000010;  
int primes[N], cnt;     // primes 数组存储所有找到的素数,cnt 记录素数的个数
bool st[N];             // st 数组标记数字是否被筛掉,false 表示未筛掉

// 线性筛法,筛选出小于等于 n 的所有素数
void get_prime(int n) {
    // 遍历 2 到 n,逐个判断每个数是否为素数
    for (int i = 2; i <= n; i++) {
        // 如果 st[i] 为 false,则 i 是素数,将其存入 primes 数组
        if (!st[i]) primes[cnt++] = i;
        
        // 遍历所有已找到的素数 primes[j]
        for (int j = 0; primes[j] <= n / i; j++) {
            // 将 i 与当前素数 primes[j] 的乘积标记为合数
            st[primes[j] * i] = true;
            
            // 如果 i 是 primes[j] 的倍数,停止筛选,因为后面的乘积已经包含该素数
            if (i % primes[j] == 0) break;
        }
    }
}

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

对比总结:

筛法名称时间复杂度空间复杂度算法思想优缺点
朴素筛法O(n√n)O(1)对于每个数 i,依次检查它是否是素数,若是素数,将其倍数标记为合数。优点:实现简单,代码直观。缺点:时间复杂度较高,筛选效率低。
埃拉托斯特尼筛法O(n log log n)O(n)从 2 开始,对于每个素数 i,将它的所有倍数标记为合数。优点:效率比朴素筛法高。缺点:每个合数可能被多次标记(即被多个素数筛掉)。
线性筛法O(n)O(n)对每个数 i,只用它的最小质因子来筛选它的倍数,保证每个合数只被标记一次。优点:筛选效率最高,时间复杂度接近线性。缺点:实现稍复杂,理解难度较高。

以上基本可以解决所有素数的问题,多写几遍板子。

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

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

相关文章

C# 泛型使用案例_C# 泛型使用整理

一、系统自带常用的泛型 1.字典&#xff0c;集合 //字典 Dictionary<string, int> dic new Dictionary<string, int>(); //泛型集合 List<int> list new List<int>(); 2.泛型委托&#xff0c;输入参数&#xff0c;输出参数 //泛型 委托---输出参…

nuclei配合burpsuite快速生成POC

nuclei配合burpsuite快速生成POC 简介 Nuclei是一款基于YAML语法模板的开发的定制化快速漏洞扫描器。它使用Go语言开发&#xff0c;具有很强的可配置性、可扩展性和易用性 官网&#xff1a;https://nuclei.projectdiscovery.io Nuclei项目地址&#xff1a;https://github.com/…

生物信息常用编辑器:轻量/强大/可定制/跨平台支持的编辑器之神 - vim

Emacs 被誉为神的编辑器&#xff0c;而 vim 是编辑器之神。本人曾经是 Emacs 的粉丝&#xff0c;不过后来不知不觉&#xff0c;已经是 vim 的重度用户&#xff0c;而 Emacs 却很长时间没用了。 如果你开始在生物信息学中编写代码或处理大量文本数据&#xff0c;选择一个合适的文…

【C语言刷力扣】2079.给植物浇水

题目&#xff1a; 解题思路&#xff1a; 面对每一株植物有两种情况 水够 or 水不够&#xff1a; 水够&#xff1a; result 加1即向前走一步水不够&#xff1a; 走回河边再走回来并向前走一步&#xff0c;走到下一植物 result 2 * i 1 int wateringPlants(int* plants, int…

Cluster Explanation via Polyhedral Descriptions

通过多面体描述进行聚类解释 本文关注聚类描述问题&#xff0c;即在给定数据集及其聚类划分的情况下&#xff0c;解释这些聚类的任务。我们提出了一种新的聚类解释方法&#xff0c;通过在每个聚类周围构建一个多面体&#xff0c;同时最小化最终多面体的复杂性或用于描述的特征…

2024-9-28 QT登录框基础练习

1.头文件 #ifndef LOGINWINDOW_H #define LOGINWINDOW_H#include <QWidget> #include <QPushButton> #include <QLineEdit> #include <QVBoxLayout>class LoginWindow : public QWidget {Q_OBJECTpublic:// 构造函数LoginWindow(QWidget *parent nul…

卸载WSL(Ubuntu),卸载linux

禁用 WSL 功能 打开 Windows 功能&#xff1a; 按下 Windows R 打开运行对话框&#xff0c;输入 optionalfeatures&#xff0c;然后按回车。 禁用 WSL&#xff1a; 在弹出的 Windows 功能窗口中&#xff0c;找到 适用于 Linux 的 Windows 子系统&#xff08;Windows Subsystem…

2024年咸宁中级职称水平测试合格公示

工程系列水测合格549人 农业系列水测合格18人 新闻系列水测合格37人 档案系列水测合格16人 看来每年评工程类职称 人员还是占大多数 关于咸宁初级、中级职称评审更多需要了解的可以留言

.NET 开源的功能强大的人脸识别 API

给大家推荐一款.NET 开源提供了强大的人脸识别 API&#xff0c;工具不仅易于集成&#xff0c;还具备高效处理能力。 本文将介绍一款如何利用这些API&#xff0c;为我们的项目添加智能识别的亮点 GitHub 上拥有 1.2k 星标的 C# 面部识别 API 项目&#xff1a;FaceRecognitionD…

传知代码-基于图神经网络的知识追踪方法(论文复现)

代码以及视频讲解 本文所涉及所有资源均在传知代码平台可获取 1.论文概述 论文链接提出了一种基于图神经网络的知识追踪方法&#xff0c;称为基于图的知识追踪&#xff08;GKT&#xff09;。将知识结构构建为图&#xff0c;其中节点对应于概念&#xff0c;边对应于它们之间的…

Jupyter Notebook 更换主题

1、安装 Jupyter 主题 pip install jupyterthemes 2、更新 Jupyter 主题 &#xff08;可选&#xff09; pip install --upgrade jupyterthemes 3、查看可用的 Jupyter 主题 jt -l 4、更换 Jupyter 主题 选择你喜欢的主题后&#xff0c;可以使用以下命令来应用它。更换主题后…

个人健康管理小程序(源码+参考文档+定制)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

Python 潮流周刊#71:PyPI 应该摆脱掉它的赞助依赖

△△请给“Python猫”加星标 &#xff0c;以免错过文章推送 本周刊由 Python猫 出品&#xff0c;精心筛选国内外的 250 信息源&#xff0c;为你挑选最值得分享的文章、教程、开源项目、软件工具、播客和视频、热门话题等内容。愿景&#xff1a;帮助所有读者精进 Python 技术&am…

如何安装和设置 Go 版本的 fabric AI 工作流框架?

痛点 今年 6 月份&#xff0c;我给你介绍了 fabric 这款 AI 工作流工具。 它包裹了大量的优秀提示词&#xff0c;可以处理各种你日常工作、学习和科研中的事务性工作。包括但不限于&#xff1a; 从视频当中提取要点撰写博客给研究评分…… 不少读者看过之后&#xff0c;大呼有用…

代码随想录Day 59|图论Part09,dijkstra(堆优化版)精讲、Bellman_ford算法精讲

提示&#xff1a;DDU&#xff0c;供自己复习使用。欢迎大家前来讨论~ 文章目录 图论part09dijkstra&#xff08;堆优化版&#xff09;精讲图的存储邻接矩阵邻接表 Bellman_ford 算法精讲模拟过程代码总结 图论part09 dijkstra&#xff08;堆优化版&#xff09;精讲 图的存储…

Windows安装启动apache httpd 2.4 web服务器

Windows安装启动apache httpd 2.4 web服务器 apache httpd主要用来处理静态网页内容以及如php。 &#xff08;1&#xff09;在 Apache VS17 binaries and modules download 下载apache&#xff1a; &#xff08;2&#xff09;下载解压到一个目录&#xff0c;如果目录是这样的…

WindowsTerminal中oh-my-posh样式的cmd、git-bash、cmder配置参数

C:\Users\root\Documents\WindowsPowerShell中写如下内容 Import-Module posh-git # 引入 posh-git Import-Module oh-my-posh # 引入 oh-my-posh Import-Module -Name Terminal-Icons # 引入文件图标库 Import-Module PSReadLine # 历史命令联想 # 设置主题 Set-PoshPrompt …

MQTT.fx 1.7.1使用说明篇(OneNET-MQTT-API调试)

&#xff08;代码完美实现&#xff09;stm32 新版 onenet mqtt物联网(保姆级教程) &#xff08;代码完美实现&#xff09;stm32 新版 onenet mqtt物联网(保姆级教程)https://blog.csdn.net/Wang2869902214/article/details/142501323 MQTT.fx 1.7.1使用教程 下载地址 MQ…