当前位置: 首页 > news >正文

算法中的数学:质数(素数)

1.质数

1.1定义

一个大于1的自然数,除了1和它自身外,不能被其他自然数整除,那么他就是质数,否则他就是合数。

注意:1既不是质数也不是合数

唯一的偶质数是2,其余所有质数都是奇质数

1.2质数判定求法

试除法:

若n为1,说明不是质数,

若n不为1,

我们从2开始遍历到n-1,判断2到n-1是否可以被n整除,如果任意(2,n-1)的数可以被整除,那么他就不是质数。如果都不能被整除,那么就是质数


上面的试除法其实还不够好,因为需要遍历的次数接近n次,而我们其实可以再剪掉一部分数不用判断。

结论:只要遍历从2到根号n的自然数

讲解:

若n有一个大于根号n的因数,那么它一定有一个小于根号n的因数(因为这样两个因数相乘才会等于n)

而一个合数一定有一个因数小于等于根号n,所以我们只要判断从2到根号n的自然数是否有关于n的因数就可以知道该数是合数还是质数了

若存在一个可以整除的数i,那么这个数n就是合数,否则他就不是合数,而是质数

代码实现:

bool isprime(int num)
{if(num == 1) return false;for(int i = 2; i <= num/i; i++){if(num%i == 0){return false;}}return true;
}

2.更多应用方法

若我们想知道区间(1,n)中一共有多少个素数,且想知道第k个素数是谁。应该如何求?

暴力解法:遍历判断(1,n),用全局变量count记录一共出现的素数个数,用数组f[k]记录第k个素数是谁

不过我们其实有其他更好的解法可以用,接下来我们分别介绍


注意:区间一定要是从1或2开始的连续区间才可以用后面的方法

2.1埃氏筛

 对于一个大于1的正整数,他的k倍一定是一个合数

所以我们在访问到当前数num的时候就可以顺便把他的所有倍数剪枝掉,他的所有倍数一定不是素数

而如果我们是从i==2开始遍历的,只要我们可以访问到的数就一定是质数,这可以用反证法推导。

图示解析前三轮:

被框柱的就是判定为素数的,被划掉的表示经过倍数筛查将这些合数筛掉了,我们看到这里其实有一些数被筛掉了两次,这是因为他们是某些质数的公倍数,而我们其实可以通过优化让我们在筛查的时候减少重复筛

优化:

我们在倍数筛查的时候可以直接从i的i倍开始,因为i的2倍到i-1倍都被前面的质数倍数筛掉了

代码实现:

typedef long long ll;
const int N = 1e9;
bool f[N];
int a[N];
int count;
void get_prime(int n)
{for(int i = 2; i <= n; i++){if(f[i] == true){ continue;}a[++count] =  i;for(ll j = i*i ; j <= n; j+=i){f[j] = true;}}
}

2.2线性筛

 由于埃氏筛即使经过从i乘i开始的优化,仍然会有合数被重复筛,时间复杂度并不是O(n)级别。

为了使筛选的时间复杂度降低为O(n)级别,我们需要使用线性筛


线性筛最多只会对每个元素访问两次,一次是遍历到的时候,一次是筛掉的时候。

核心逻辑:让每个合数被其最小质因数筛掉

代码实现核心逻辑:

从前往后遍历数i,用i的质数倍去筛,当i是当前的质数的倍数时,进行完当前筛查后停止

代码实现:
 

typedef long long ll;
const int N = 1e9;
bool f[N];
int a[N];
int count;
void get_prime(int n)
{for(ll i = 2; i <= n; i++){
//没有被标记为true,说明是质数if(f[i] == false) {a[++count] = i;}
//进行线性筛for(int j = 1; i*a[j] <= n; j++){f[i*a[j]] = true;if(i % a[j] == 0) break;{          }
}

注意:

1.如果i是合数,那么他会枚举到最小质因数后退出循环;如果i是质数,那么他会枚举到等于它本身的质数后退出循环。

而这个特性表明:p[j]就是i的最小质因数

2.线性筛的for循环条件中没有j<=count是因为当j==count的时候,i==p[j],直接break了

2.3例题讲解

审题:
本题需要我们找出区间l到r之间的所有素数的个数

思路:

方法一:暴力解法

我们用双层for循环,外层for循环将l到r遍历,内层将1~根i的数与外层的数依次试除,然后若有一次成功整除则i为素数,count++。

时间上:外层为1e6,内层为1e6,所以总共的运行次数可能会达到1e12,会超时

方法二:二次筛选

我们其实不用将1到r的所有素数都选出来,而是只要遍历到根号r即可将1到r的素数筛选出来。

然后我们的筛选方法不用试除法,因为该方法要对每一个数都进行n次,所以使用埃氏筛。

第一步:将1到根号r的质数筛选出来

第二步:利用筛选出来的质数再利用埃氏筛的方法筛选出l到r之间的素数

第三步:记录区间素数个数并输出

注意:
1.筛选1到根号r的素数的目的是利用埃氏筛进行l到r的筛选

2.如何确定质数的起始倍数?
因为我们的l不是从1或2开始的,所以质数的较低倍数可能会小于l,我们为了避免这种无效筛选就要找到质数合适的起始倍数。

而该质数乘上起始倍数一定要大于等于l的值

于是我们得出以下向上取整的倍数计算式:   l+x-1/x

解析:原本l/x就可以大概得到所需倍数,但是可能因为被计算机向下取整导致计算结果仍小于l,所以我们在分子加上x-1就进行了向上取整的操作

解题:
 

#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
ll l, r;
int cou;//记录1~根号r的素数个数
ll prime[N];//记录素数
bool f[N];//埃氏筛筛查表
bool F[N];
void selprime()
{for (ll i = 2; i <= sqrt(r); i++){if (F[i] == true)//被筛掉了{continue;}else{prime[cou++] = i;ll j = i;while (j * i <= sqrt(r))//进行标记{F[j * i] = true;j++;}}}
}
int main()
{cin >> l >> r;l = l == 1 ? 2 : l;//控制l不为1//筛选1~根号r的素数selprime();//利用埃氏筛和选出的素数对l到r区域进行筛选for (int i = 0; i < cou; i++){ll x = prime[i];for (ll j = max(2 * x, (l + x - 1) / x * x); j <= r; j += x){f[j-l] = true;}}//记录区间素数个数ll count = 0;for (ll i = l; i <= r; i++){if (f[i-l] == false)count++;}cout << count << endl;return 0;
}

1.我们的第一次筛选使用的是埃氏筛,所以利用了一个F数组来记录筛选结果。

2.由于1既不是合数也不是素数,所以我们将l为1的情况变为l为2

3.若出现l的值和筛选出的质数的值一样的情况,也就是起始倍数为1,我们不能对它打上true标记,因为他是质数,所以我们加一个判断,若倍数为1则将倍数设置为2进行筛选

4.由于l和r的数据范围较大,为了合法记录筛选情况,我们不能直接用f[j]记录情况,而是要将j情况映射到j-l处,因为l和r之间的差小于1e6,我们是可以记录的

相关文章:

  • chili3d笔记11 连接yolo python http.server 跨域请求 flask
  • CRS 16 slot 设备硬件架构
  • [学成在线]23-面试题总结
  • window 系统 使用ollama + docker + deepseek R1+ Dify 搭建本地个人助手
  • GZIPOutputStream 类详解
  • GPIO引脚的上拉下拉以及转换速度到底怎么选
  • macbook install chromedriver
  • linux 中inotify与inode的关系是什么?
  • Linux系统编程--基础指令(!!详细讲解+知识拓展)
  • [人机交互]交互设计
  • 物联网mqtt和互联网http协议区别
  • 经典的 Masked + Self-supervised learning 的模型方法
  • “Copy-On-Write” (COW)
  • 基于思考过程评价的心理问题咨询对话记性评估
  • 端口(Port)
  • 【Java ee初阶】多线程(5)
  • 提示词压缩方法总结与开源工具包
  • 1. 设计哲学:让字面量“活”起来,提升表达力和安全性
  • Spring Boot 加载application.properties或application.yml配置文件的位置顺序。
  • Nacos源码—3.Nacos集群高可用分析一
  • 交通运输部、水利部同日召开会议,深刻汲取贵州游船倾覆事故教训
  • 宋涛就许历农逝世向其家属致唁电
  • 新剧|《执法者们》《亲爱的仇敌》5月7日开播
  • 猎金,游戏,诚不我欺
  • 缔造“水饺皇后”的香港,也是被移民塑造的香港
  • 巴菲特股东大会前瞻:执掌伯克希尔60年,巨轮将驶向何方