素数(埃式筛法、线性筛法)

2023-11-14

 


 
 

  

素数判断方法

最简单的就是从 2 ~ n-1 都去与 n 取余,看是否能整除。

bool prime(int n){
	for(int i = 2; i < n; i ++)
		if(n % i == 0)
			return true;
	return false;
}

思考一下:其实没有必要枚举所有的比 n 小的数,n % i == 0,那么必定有一个 j 使得 i * j = n。所以只需要枚举 i * i ≤ n 的 i 就可以了。

bool prime(int n){
	for(int i = 2; i * i <= n; i ++)
		if(n % i == 0)
			return true;
	return false;
}

 
 

 
 

 
 

埃式筛法

如果需要对许多整数进行素数判断,上面得方法时间复杂度就较高了,这就需要更高效的算法,如埃式筛法。

一个数如果是素数,那么它的倍数就一定是合数,这就筛去了它的所有倍数。

操作:将 2 ~ n-1 个整数列出来,从 2 开始把它的倍数都筛去,然后将 3 的倍数筛去……遍历所有的素数,把它的倍数都筛去。
我们设置一个标记数组,依次遍历过去(同时标记它的倍数),若 i 没有被标记就代表 i 不会被 2 ~ i-1 的任何一个整数整除,就说明它是素数。

埃式筛法图示

bool flag[maxx];
int prime[maxx], p;//记录素数 
void primes(int n){
	flag[1] = true;
	for(int i = 2; i <= n; i ++){
		if(!flag[i]){//找到一个素数 
			prime[p ++] = i;//记录素数 
		}
		for(int j = 0; prime[j] * i <= n; j ++)//遍历素数数组,将全部素数的i倍进行标记 
			flag[prime[j] * i] = true;
	}
}

时间复杂度:O(n * log log n)
n = 12的埃式筛法流程

i prime 本轮筛去的整数
2 2 4
3 2、3 6、9
4 2、3 8、12
5 2、3、5 10
6 2、3、5 12
7 2、3、5、7
8 2、3、5、7
9 2、3、5、7
10 2、3、5、7
11 2、3、5、7、11
12 2、3、5、7、11

 
 

 
 

 
 

线性筛法

仔细思考一下:埃式筛法也有冗余,同一个合数有可能会被两个素数筛。例如,12:12 % 2 = 0、12 % 3 = 0,那么 12 就被 2、3 都筛了一次,这样就导致了重复。

线性筛法保证每个合数只会被它的最小质因数筛去,因此每个数只会被标记一次,时间复杂度是O(n)。

bool flag[maxx];
int prime[maxx], p;//记录素数 
void primes(int n){
	flag[1] = true;
	for(int i = 2; i <= n; i ++){
		if(!flag[i]){//找到一个素数 
			prime[p ++] = i;//记录素数 
		}
		for(int j = 0; prime[j] * i <= n; j ++){
			flag[i * prime[j]] = true;
			if(i % prime[j] == 0)
				break;
		} 
	}
}

这与埃式筛法的区别就在于:

if(i % prime[j] == 0)
  break;

这样就保证了同一个合数,只会被他最小的质因子筛去。
证明: 如果 i % prime[j] = 0,记 k = i / prime[j],则 i * prime[j + 1] = k * prime[j] * prime[j + 1],而 prime[j] < prime[j + 1],则代表 prime[j + 1] 不是 i * prime[j + 1] 的最小质因子。

我看一下上面举的例子:12

i prime 本轮筛去的整数
2 2 4
3 2、3 6、9
4 2、3 8(4 % 2 = 0)
5 2、3、5 10
6 2、3、5 12(6 % 2 = 0)
7 2、3、5、7
8 2、3、5、7
9 2、3、5、7
10 2、3、5、7
11 2、3、5、7、11
12 2、3、5、7、11

 
 

 
 

 
 

区间筛法

问题:给定整数 a 和 b,请问区间 [a, b) 内有多少个素数?

思路:b 以内的合数的最小质因数一定不超过 sqrt(b)。如果有 sqrt(b) 以内的素数表的话,就可以把埃氏筛法运用在 [a, b) 上了。也就是说,先分别做好 [2, sqrt(b)) 的表和 [a, b) 的表,然后从 [2, sqrt(b)) 的表中筛得素数的同时,也将其倍数从 [a, b) 的表中划去,最后剩下的就是 [a, b) 内的素数了。

bool flag[maxx], flag_section[maxx];
int primes(int a, int b){
	flag[1] = true;
	for(int i = 2; i * i < b; i ++){
		if(!flag[i]){//找到一个素数  
			for(int j = 2 * i; j * j < b; j += i)//筛选[2, sqrt(b)) 
				flag[j] = true;
			for(int j = max(2, (a + i - 1) / i) * i; j < b; j += i)//(a+i-1)/i得到最接近a的i的倍数,最低是i的2倍,然后筛选
				flag_section[j - a] = true;
		}
	}
	int cnt = 0;
	for(int i = 0; i < b - a; i ++)
		if(!flag_section[i])
			cnt ++;
	return cnt;
}

 
 

 
 

 
 

质因数分解

基本定理:任何一个大于 1 的正整数都能唯一分解为有限个质数的乘积,可写作:
N = p 1 c 1 p 2 c 2 p 3 c 3 … p m c m N=p_{1}^{c_{1}}p_{2}^{c_{2}}p_{3}^{c_{3}}\ldots p_{m}^{c_{m}} N=p1c1p2c2p3c3pmcm其中 ci 都是正整数,pi 都是质数,且满足 p1<p2<……<pm

采用:试除法。
  结合质数判定的“试除法”和质数筛选的“埃式筛法”,我们可以扫描 2~⌊ √N ⌋ 的每个数 d,若 d 能整除 N,则从 N 中除掉所有的因子 d,同时累计除去的 d 的个数。
  因为一个合数的因子一定在扫描到这个合数之前就从 N 中被除掉了,所以在上述过程中能整除 N 的一定是质数。最终就得到了质因数分解的结果,易知时间复杂度为 O(√N)。
  特别地,若 N 没有被任何 2~√N 地数整除,则 N 是质数,无需分解。

void divide(int n){
	int m = 0;
	for(int i = 2; i <= sqrt(n); i ++)
		if(n % i == 0){//i是质数 
			p[++m] = i, c[m] = 0;
			while(n % i == 0)
				n /= i, c[m] ++;
		}
	if(n > 1)//n是质数 
		p[++m] = n, c[m] = 1;
	for(int i = 1; i <= m; i ++)
		printf("%d^%d\n", p[i], c[i]);
} 

 
 

 
 

 
 

例题

第一题

题目1题目2
题目链接

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 1000010;

int primes[N], cnt;
bool st[N];

void getPrimes(int n){
	memset(st, false, sizeof(st));
	cnt = 0;
	for(int i = 2; i <= n; i ++){
		if(!st[i])
			primes[cnt ++] = i;
		for(int j = 0; primes[j] * i <= n; j ++){
			st[primes[j] * i] = true;
			if(i % primes[j] == 0)
				break;
		}
	}
}

int main(){
	long long l, r;
	while(~scanf("%lld %lld", &l, &r)){
		getPrimes(50000);
		memset(st, false, sizeof(st));
		for(int i = 0; i < cnt; i ++){
			int p = primes[i];
			for(long long j = max((l + p - 1) / p * p, 2ll * p); j <= r; j += p)// 把[l, r]中所有p的倍数筛掉
				st[j - l] = true;
		}
		
		cnt = 0;
		for(int i = 0; i <= r - l; i ++)
			if(!st[i] && i + l > 1)
				primes[cnt ++] = i + l;
		
		if(cnt < 2)
			printf("There are no adjacent primes.\n");
		else{
			int minp = 0, maxp = 0;
			for(int i = 0; i + 1 < cnt; i ++){
				int d = primes[i + 1] - primes[i];
				if(d < primes[minp + 1] - primes[minp])
					minp = i;
				if(d > primes[maxp + 1] - primes[maxp])
					maxp = i;
			}
			printf("%d,%d are closest, %d,%d are most distant.\n", primes[minp], primes[minp + 1], primes[maxp], primes[maxp + 1]);
		}
	}
	return 0;
}

 
 

 
 

 
 

第二题

题目
题目链接

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 1000010;

int primes[N], cnt;
bool st[N];

void getPrimes(int n){
	memset(st, false, sizeof(st));
	cnt = 0;
	for(int i = 2; i <= n; i ++){
		if(!st[i])
			primes[cnt ++] = i;
		for(int j = 0; primes[j] * i <= n; j ++){
			st[primes[j] * i] = true;
			if(i % primes[j] == 0)
				break;
		}
	}
}

int main(){
	int n;
	scanf("%d", &n);
	getPrimes(n);
	
	for(int i = 0; i < cnt; i ++){
		int p = primes[i];
		int s = 0;
		for(int j = p; j <= n; j *= p){
			s += n / j;
			if(j > n / p)
				break;
		}
		printf("%d %d\n", p, s);
	}
	return 0;
}

 
 

 
 

 
 

第三题

题目
题目链接

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 1000010;

int primes[N], cnt;
bool st[N];

void getPrimes(int n){
	memset(st, false, sizeof(st));
	cnt = 0;
	for(int i = 2; i <= n; i ++){
		if(!st[i])
			primes[cnt ++] = i;
		for(int j = 0; primes[j] * i <= n; j ++){
			st[primes[j] * i] = true;
			if(i % primes[j] == 0)
				break;
		}
	}
}

int main()
{
  // 请在此输入您的代码
  getPrimes(2019);
  long long dp[2020] = {1};
  for(int i = 0; i < cnt; i ++)
    for(int j = 2019; j >= primes[i]; j --)
      dp[j] += dp[j - primes[i]];
  printf("%lld", dp[2019]);
  return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

素数(埃式筛法、线性筛法) 的相关文章

  • 为 DocumentDb 设置自定义 json 转换器

    我正在使用类型化 DocumentQuery 从 Azure DocumentDb 集合中读取文档 from f in client CreateDocumentQuery
  • 如何使用C从http下载文件?

    最近几天我试图弄清楚如何从 URL 下载文件 这是我对套接字的第一个挑战 我用它来了解协议 所以我想在没有 cURL 库的情况下只用 C 语言来完成它 我搜索了很多 现在我可以打印页面的源代码 但我认为这与文件不同 我不必只将接收到的数据从
  • 错误:表达式不可赋值三元运算符

    我有以下代码 MPLABX XC8 编译器给出此错误 错误 表达式不可分配 U1ERRIRbits RXFOIF uart1 oerr 1 uart1 oerr 0 这是相关代码部分 typedef union struct bool fe
  • 并行运行多个任务

    我有一个代理列表 每个代理都会访问不同的站点并从站点中提取所需的数据 目前它一次只做一个 但我希望同时运行 10 20 个任务 这样它就可以一次性从 20 个站点下载 而不是只下载一个 这是我目前正在做的事情 private async T
  • 如何在 Linux 上重新实现(或包装)系统调用函数?

    假设我想完全接管 open 系统调用 也许要包装实际的系统调用并执行一些日志记录 一种方法是使用 LD PRELOAD http scaryreasoner wordpress com 2007 11 17 using ld preload
  • 在 C# 中解析 JS Date.toIsoString

    我需要将 JS 日期存储为 ISO 8601 日期 我目前正在从格式为 2019 06 22T00 00 00 000Z 的表单中获取日期 正如 JS 的 toIsoString 方法所期望的那样 当这个日期传递到我的 API 控制器时 我
  • 公交车公共交通算法

    我正在开发一个可以查找公交路线的离线 C 应用程序 我可以提取时间表 巴士 路线数据 我正在寻找适用于基本数据的最简单的解决方案 可以使用什么算法来查找从巴士站 A 到巴士站 B 的路线 是否有适用于 C Java 的开源解决方案 数据库的
  • 重载算术运算符

    赋值运算符可以声明为 T 运算符 const t 在类中 但不能以这种方式定义算术运算符 它必须是友元函数 我不明白为什么 你能解释一下吗 算术运算符不必须是友元 那么你可以这样定义 MyClass MyClass operator con
  • ASP.NET - Crystal Report Viewer 打印按钮在 ASP.NET 中不起作用

    我正在使用 Visual Studio 2008 但我遇到了水晶报告问题 当我单击打印按钮时 它会将我带到弹出窗口 但未找到页面 弹出的网址是 http localhost aspnet client System Web 2 0 5072
  • 为什么连续抛出 2 个异常不会生成无法访问的代码警告?

    为什么以下代码行不会创建编译器警告 void Main throw new Exception throw new Exception 据我所知 编译器应该通知您无法到达第二个抛出异常 这显然是一个编译器错误 它是在 C 3 0 中引入的
  • C# 可以为控制台应用程序部分类“程序”类吗?

    我想知道是否可以将为任何控制台应用程序创建的默认 程序 类更改为部分类 我想这样做是因为我想要更好的组织 而不是将所有方法都放在按区域分类的 1 个文件中 对我来说 将某些方法类别放在单独的文件中会更有意义 我对分部类的理解是 它是多个文件
  • 运行实体框架自定义工具,它有什么作用?

    在 Visual Studio 中 当使用实体框架并为 tt 和 Context tt 文件应用运行自定义工具时 它是什么以及它有什么作用 为什么它解决数据库同步问题 有时 为什么我应该在运行 tt 之前运行它 Context tt 它被称
  • 如何在Windows窗体中打开进程

    我想在我的 Windows 窗体应用程序中打开进程 例如 我希望当用户按下 Windows 窗体容器之一中的按钮时 mstsc exe 将打开 如果他按下按钮 它将在另一个容器上打开 IE DllImport user32 dll SetL
  • 如何在VS2005中使用从.bat而不是.exe启动的外部程序进行调试?

    在我的 c 项目的调试属性中 我选择了 启动外部程序 并选择了我希望将调试器附加到的程序的 exe 但是 现在我需要从 bat 文件而不是 exe 启动程序 但 VS2005 似乎不允许这样做 这可能吗 编辑 为了澄清 我需要调试从 bat
  • 从单应性估计 R/T

    我一直在尝试计算 2 个图像中的特征 然后将这些特征传递回CameraParams R没有运气 特征已成功计算并匹配 但是问题是将它们传递回R t 我明白你必须分解Homography为了使这一点成为可能 我已经使用如下方法完成了 http
  • 使用未命名命名空间而不是静态命名空间

    我可以假设在未命名命名空间中声明的对象相当于static namespace int x 1 static int x 2 FWIK 在这两种情况下 x将具有静态存储期限和内部链接 声明为的对象的所有规则也是如此static适用于未命名名称
  • 如何防止 Lotus Notes 用户转发或复制通过 System.Net.Mail 发送的邮件?

    我想使用 SMTP 客户端 uiing microsft net 以 C 作为编程语言发送电子邮件 但是对于通过SMTP客户端发送的电子邮件 我们是否可以添加 禁止转发 或 禁止复制 等安全功能 我不希望电子邮件的收件人转发或复制电子邮件的
  • 稀疏矩阵超定线性方程组c/c++库

    我需要一个库来解决 Ax b 系统 其中 A 是一个非对称稀疏矩阵 每行有 8 个条目 而且可能很大 我认为实现双共轭梯度的库应该没问题 但我找不到一个有效的库 我尝试过 iml 但 iml sparselib 包中缺少一些标头 有小费吗
  • 使用空的weak_ptr作为参数调用map::count安全吗?

    打电话安全吗map count http www cplusplus com reference map map count on an 未初始化因此为空weak ptr http en cppreference com w cpp mem
  • 将同步 zip 操作转换为异步

    我们有一个现有的库 其中一些方法需要转换为异步方法 但是我不确定如何使用以下方法执行此操作 错误处理已被删除 该方法的目的是压缩文件并将其保存到磁盘 请注意 zip 类不公开任何异步方法 public static bool ZipAndS

随机推荐

  • Spring属性注入方式

    1 Spring也表示一个开源框架 是为了解决企业程序应用开发的复杂性 框架的主要优势之一就是其分层架构 分层架构允许使用者选择使用哪一个组件 同时为J2EE应用程序开发提供集成的框架 Spring使用基本的bean来完成以前只能由EJB完
  • idea乱码解决方式大汇总

    目录 idea版本 解决方法 一 基本方法 1 File gt Settings gt Editor 2 二 Maven乱码解决方法 三 运行时乱码解决方法 四 因为以前乱设置导致的乱码 idea版本 解决方法 一 基本方法 1 File
  • 华为telnet学习笔记

    华为telnet用户密码aaa模式 配置完接口后 aaa local user admin password cipher cisco 创建用户设置账号密码 local user admin service type telnet 为这个用
  • QLUACM暑假训练5 C题题解

    C题题目大意 给一个n行m列的矩阵 矩阵的每个元素由 或者 填充 如果一行或者一列都由 构成 则删除这一行或者这一列 最后按照相对位置输出剩余的元素 题解 题目思路 1 我们需要找出一行或者一列都由 构成的行和列的位置 也就是我们需要找到没
  • 图像分割套件PaddleSeg全面解析(五)模型与Backbone代码解读

    本章节将介绍PaddleSeg的核心部分 分割模型和主干网络部分 在yaml配置文件中有以下定义 模型信息 model 模型的类型FCN type FCN 使用的主干网络为HRNet backbone type HRNet W18 主干网络
  • 宋浩高等数学笔记(六)定积分的应用

    本章继续更新高数笔记 6 5节的物理题暂不更新 有需求的同学自行看课
  • R语言:创建数据集

    文章目录 1 创建数据集 1 1 数据集的概念 1 2 数据结构 1 2 1 向量 1 2 2 矩阵 1 2 3 数组 1 2 4 数据框 data frame 的切片 attach detach 和with 实例标识符 1 2 5 因子
  • Flutter桌面小工具 -- 灵动岛【Windows+Android版本】

    通过此篇文章 你将了解到 Flutter动画实现灵动岛 Flutter如何开发一个置顶可自由拖拽的小工具 分享一些关于灵动岛的想法 本文为稀土掘金技术社区首发签约文章 14天内禁止转载 14天后未获授权禁止转载 侵权必究 前言 Flutte
  • FormData(file类型文件)

    有的时候我们上传图片时 后台要求是file类型 我们可以借助FormData 以这种方式上传的 后台接收到的 window files self files 0 if window files var form new FormData v
  • [Python从零到壹] 十.网络爬虫之Selenium爬取在线百科知识万字详解(NLP语料构造必备技能)

    欢迎大家来到 Python从零到壹 在这里我将分享约200篇Python系列文章 带大家一起去学习和玩耍 看看Python这个有趣的世界 所有文章都将结合案例 代码和作者的经验讲解 真心想把自己近十年的编程经验分享给大家 希望对您有所帮助
  • sql计算留存率

    SELECT first day sum case when by day 0 then 1 else 0 end day 0 sum case when by day 1 then 1 else 0 end day 1 sum case
  • 解决WebSocketClient.js?5586:16 WebSocket connection to ‘ws://192.168.1.102:8999/ws‘ failed:

    修改vue config js里的devServer配置 添加client 配置 client webSocketURL ws 0 0 0 0 8999 ws module exports 配置跨域请求 devServer 项目运行的端口号
  • frida辅助分析ollvm字符串加密

    frida辅助分析ollvm字符串加密 近期逆向任务繁重且艰巨 因此把工作期间得学习心得做下笔记还是十分得有必要得 防止后期遗忘 个人博客 http www zhuoyue360 com 文章目录 frida辅助分析ollvm字符串加密 一
  • JAVA解析纯真IP地址库

    前几天看了下Ruby的IPParse 觉得很过瘾 上网查了下貌似很多IP数据库都要收费的 就下了个纯真QQIP地址库 发现还可以在线升级的 很适合咱做点小玩意 具体解析的纯真版IP地址库请详见http lumaqq linuxsir org
  • Discuz!开发之主题高亮字段highlight解析

    Discuz 开发之主题高亮字段highlight解析 相关数据表pre forum thread 我们可以看到主题高亮信息存储于字段highlight 且为一个整型数据 那么discuz 如何将这个整型数解析为高亮 包括 字体颜色 背景颜
  • FPGA开发流程概述

    Lesson 3 FPGA开发流程概述 开始学习FPGA 想尽快上手FPGA开发 那么先来了解一下FPGA的开发流程 1 需求分析到模块划分 需求说明文档 器件选择 逻辑资源 功耗 IO数量 封装等等 配置电路考虑 开发工具选择 电路板的可
  • 数据结构与算法实验-实验一:线性表基本操作

    线性表基本操作 文章目录 线性表基本操作 题目1 题目2 题目3 题目1 线性表是最常见和常用的ADT 假设线性表的元素为整数 请基于顺序存储结构实现线性表ADT 基本功能包括 1 建立线性表 输入有两行 第一行是一个整数n 线性表的长度
  • SpringMVC自定义视图完成步骤 和 视图解析的源码剖析

    自定义视图完成步骤 7 2 1自定义视图完成步骤 1 自定义视图 创建一个 View 的 bean 该 bean 需要继承自 AbstractView 并实现 renderMergedOutputModel 方法 2 并把自定义 View
  • 【项目实战】在win10上安装配置Hadoop的环境变量

    一 说明 注意 该教程适用于 远程连接Linux上的Hadoop集群 因此本步骤是不需要在本地再下载hadoop的 在win10操作系统上 运行Hadoop以及其相关依赖包 比如Hbase依赖包 时 我遇到的情况是 我需要使用SpringB
  • 素数(埃式筛法、线性筛法)

    文章目录 素数判断方法 埃式筛法 线性筛法 区间筛法 质因数分解 例题 第一题 第二题 第三题 素数判断方法 最简单的就是从 2 n 1 都去与 n 取余 看是否能整除 bool prime int n for int i 2 i lt n