数论——质数和合数及求质数

news2025/6/3 15:45:46

质数和合数及求质数

一个大于 1 的自然数,除了 1 和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数。其中,质数又称素数。有的资料用的词不同,但质数和素数其实是一回事。

规定 1 既不是质数也不是合数。

试除法判断质数

  • 对于一个数 x x x,根据定义,可以从 [ 2 , x − 1 ] [2, x - 1] [2,x1] 一个一个尝试,判断 x x x 能否被整除。

但是,没有必要每一个都去判断。因为 a a a 如果是 x x x 的约数,那么 x / a x / a x/a 也是 x x x 的约数。因此,我们仅需判断较小的 a a a 是否是 x x x 的约数,没有必要再去看看 x / a x / a x/a。那么,仅需枚举到 x \sqrt{x} x 即可。

试除法实现:

bool prim(int x) {
	if (x < 2)
		return false;
	for (int i = 2; i <= x / i; i++)//i*i<=x,所以i<=x/i,这是防溢出写法
		if (x % i == 0)
			return false;
	return true;
}

时间复杂度:因为是枚举到 n \sqrt{n} n ,所以时间复杂度为 O ( N ) O(\sqrt{N}) O(N )

模板题:

P5736 【深基7.例2】质数筛 - 洛谷

#include<bits/stdc++.h>
using namespace std;

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

int main() {
	int n; cin >> n;
	for (int x = 0; n--;) {
		cin >> x;
		if (prim(x))
			cout << x << ' ';
	}
	return 0;
}

Eratosthenes筛选法(埃氏筛)

模板题:P3383 【模板】线性筛素数 - 洛谷

在很多场景我们需要知道[2, n]内有多少个质数,或正数、倒数第 k k k个质数是多少。 n n n 很有可能特别大,此时传统的试除法一个一个判断显然会很慢甚至无法在规定时间内完成判断。因此需要使用其他算法来筛选出指定范围内的质数。

Eratosthenes筛选法基本思想:质数的倍数一定不是质数。

实现方法:用一个长度为 N + 1 N+1 N+1 的数组vis保存信息(0 表示质数,1 表示非质数),先假设所有的数都是质数(初始化为 0),从小到大枚举每一个质数 x x x,把 x x x 的倍数都标记为非质数(置为 1)。当从小到大扫描时扫描到一个数 x x x ,若它尚未被标记,则它不能被 2 ∼ x − 1 2 \sim x-1 2x1 之间的任何数整除,该数就是质数。

整数 1 特殊处理即可。在筛数的时候可以从 x 2 x^2 x2开始筛,因为小于 x x x的合数是被筛选过的。

//Eratosthenes筛(埃氏筛)
void get_prim(vector<int>&vis, vector<int>&ans) {
	for (size_t i = 2; i < vis.size(); i++) {
		if (vis[i])
			continue;
        //记录素数
		ans.push_back(i);
        //从i*i开始,因为小于i的合数已经被筛掉了
		for (size_t j = i * i; j < vis.size(); j+=i)
			vis[j] = true;//筛掉合数
	}
}

时间复杂度(推荐直接记结论): O ( n log ⁡ log ⁡ n ) O(n\log\log n) O(nloglogn)。这里 n n n实际就是vis.size()

严谨的数学推导:埃氏筛法的时间复杂度的详细证明-CSDN博客

P3383 【模板】线性筛素数 - 洛谷参考程序(埃氏筛):

#include<bits/stdc++.h>
using namespace std;

void Eratosthenes(vector<bool>& vis, vector<int>& ans) {
	for (size_t i = 2; i < vis.size(); i++) {
		if (vis[i])
			continue;
		ans.push_back(i);
		for (size_t j = i * i; j < vis.size(); j += i)
			vis[j] = true;
	}
}

int main() {
	int n, q,num;
	scanf("%d %d", &n, &q);
	vector<bool>vis(n + 1, false);
	vector<int>ans;
	Eratosthenes(vis, ans);//埃氏筛
	while (q--) {
		scanf("%d", &num);
		cout << ans[num - 1] << endl;
	}
	return 0;
}

线性筛(欧拉筛)

线性筛法,又称欧拉筛法。在埃氏筛法中,它会将一个合数重复多次标记。如果能让每个合数都只被标记一次,那么时间复杂度就可以降到 O ( n ) O(n) O(n)

我们的做法是,让每一个合数被它的最小质因数筛掉

void get_prim(vector<int>& vis, vector<int>& ans) {
	for (size_t i = 2; i < vis.size(); i++) {
		if (!vis[i])//被标记为true时是合数
			ans.push_back(i);
        //1uLL是为了让size_t强制转换成unsigned long long防止溢出
		for (size_t j = 0; 1uLL * i * ans[j] < vis.size(); j++) {
			//筛掉合数
			vis[i * ans[j]] = true;
			//i是质数的倍数时停止,当i正好为最后一个质数时循环终止
			if (i % ans[j] == 0)
				break;
		}
	}
}

i%ans[j]==0这个判定条件能让每一个合数被自己的最小质因数筛掉。

  1. 如果 i 是合数,枚举到最小质因数的时候跳出循环
  2. 如果 i 是质数,枚举到自身时跳出循环
    注意,在筛的过程中,我们还能知道 p[j]i 的最小质因数

这个算法最多遍历2遍数组,也就是说实际的时间复杂度是 O ( 2 n ) O(2n) O(2n)

很多和数学有关的算法都是在欧拉筛的基础上实现(例如积性函数),因此欧拉筛很重要,需要理解这个算法的本质。

P3383 【模板】线性筛素数 - 洛谷参考程序(欧拉筛):

#include<bits/stdc++.h>
using namespace std;

void Euler(vector<bool>& vis, vector<int>& ans) {
	for (size_t i = 2; i < vis.size(); i++) {
		if (!vis[i])
			ans.push_back(i);
		for (size_t j = 0; 1uLL * i * ans[j] < vis.size(); j++) {
			vis[i * ans[j]] = true;
			if (i % ans[j] == 0)
				break;
		}
	}
}

int main() {
	int n, q,num;
	scanf("%d %d", &n, &q);
	vector<bool>vis(n + 1, false);
	vector<int>ans;
	Euler(vis, ans);//欧拉筛
	while (q--) {
		scanf("%d", &num);
		cout << ans[num - 1] << endl;
	}
	return 0;
}

质数有关OJ列举

P1835 素数密度 - 洛谷

P1835 素数密度 - 洛谷

因为 1 ≤ L ≤ R ≤ 2 31 1\leq L\leq R\leq 2^{31} 1LR231,无论是埃氏筛还是线性筛,在空间上会超限,在时间上遍历 2 31 2^{31} 231 O ( n ) O(n) O(n)的算法也无法在1秒内完成。

根据试除法,求一个数 r r r是否是质数,只需枚举 [ 1 , r ] [1, \sqrt{r}] [1,r ]

所以代码思路:

  • 先找出 [ 1 , R ] [1, \sqrt{R}] [1,R ]内的质数,再利用这些质数将 [ L , R ] [L,R] [L,R]内的合数标记。 R \sqrt{R} R 的数据范围是 [ 2 , 2 16 ] [2,2^{16}] [2,216] 2 16 = 65536 2^{16}=65536 216=65536,在可接受范围内,用埃氏筛或欧拉筛都可以。
  • 找到这些质数在 [ L , R ] [L,R] [L,R]内的最小合数后,用埃氏筛的做法标记 [ L , R ] [L,R] [L,R]内的其他合数。首先需要找到质数在 [ L , R ] [L,R] [L,R]的最小倍数。
    所以整体思路是埃氏筛 + 欧拉筛。

找质数在 [ L , R ] [L,R] [L,R]内的最小倍数:假设 p ∈ [ 1 , R ] p\in [1,\sqrt{R}] p[1,R ] p p p是质数,则 k p ≥ L kp\geq L kpL k ≥ ⌈ L p ⌉ k\geq \lceil\frac{L}{p}\rceil kpL,也就是说可以通过左端点除以质数并向上取整,再乘质数,即可得到最小倍数。即 ⌈ L p ⌉ × p \lceil\frac{L}{p}\rceil\times p pL×p

在计算机中求 ⌈ L p ⌉ \lceil\frac{L}{p}\rceil pL,特别是c++默认整数除法/会去除小数部分,所以可以通过对 L + ( p − 1 ) p \frac{L+(p-1)}{p} pL+(p1)向下取整来间接求得 ⌈ L p ⌉ \lceil\frac{L}{p}\rceil pL

  • L L L p p p的倍数,后面的 p − 1 p-1 p1对整体不构成影响;
  • 若不是,则在浮点数的视角, L p \frac{L}{p} pL会残留有小数部分,这一部分加上 p − 1 p \frac{p-1}{p} pp1大于1,所以通过 ⌊ L + ( p − 1 ) p ⌋ \lfloor\frac{L+(p-1)}{p}\rfloor pL+(p1)也能间接求得 ⌈ L p ⌉ \lceil\frac{L}{p}\rceil pL

综上, ⌊ L + ( p − 1 ) p ⌋ = ⌈ L p ⌉ \lfloor\frac{L+(p-1)}{p}\rfloor=\lceil\frac{L}{p}\rceil pL+(p1)=pL。在代码中可通过(L+p-1)/p*p得到质数 p p p的不小于 L L L的最小倍数。

其中需要注意的细节:

  1. L = 1 L=1 L=1,但1不是质数,所以此时需要从 L = 2 L=2 L=2开始。
  2. L ∈ [ 1 , R ] L\in [1,\sqrt{R}] L[1,R ] L L L可能是质数。
    例如{2,3,5},要求筛掉[5,25]中的合数, ⌊ 5 + 5 − 1 5 ⌋ × 5 = 5 \lfloor\frac{5+5-1}{5}\rfloor\times 5=5 55+51×5=5,因此会把5筛掉,但5是质数不能被筛掉,因为之前较小的质数已经把部分合数给晒掉了,所以若枚举到质数 p p p,则从 2 p 2p 2p开始筛,因此在使用埃氏筛的方法筛掉合数时可以从 max ⁡ ( 2 p , ⌊ L + ( p − 1 ) p ⌋ ) \max(2p,\lfloor\frac{L+(p-1)}{p}\rfloor) max(2p,pL+(p1)⌋)开始。
  3. 因为 R R R是有可能到 2 31 2^{31} 231,数组不可能开这么大,但可以通过小区间[0,R-L]来存储[L,R]的结果,再开一个 10 6 10^6 106的数组勉强能接受。
  4. 因为数据量整体过大,只有放弃vector转用一般的数组才能不超时。
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 1e6 + 10;
bool vis1[N], vis2[N];//因为超时,不得不换成普通数组
int ans[N], pans;
int L, R;

void get_prim() {
	size_t n = sqrt(R);
	for (size_t i = 2; i <= n; i++) {
		if (!vis1[i])
			ans[++pans]=i;
		for (size_t j = 1; 1ull * i * ans[j] <= n; j++) {
			vis1[i * ans[j]] = 1;
			if (i % ans[j] == 0)
				break;
		}
	}
}

int main() {
	cin >> L >> R;
	get_prim();
	L = L == 1 ? 2 : L;
	for (int i = 1; i <= pans;i++) {
		int x = ans[i];
		for (LL i = max(x * 2, (L + x - 1) / x * x);i<=R; i+=x) {
			vis2[i - L] = 1;
		}
	}
	int cnt = 0;
	for (int i = L; i <= R; i++) 
		if (!vis2[i - L])
			++cnt;
	cout << cnt;
	return 0;
}

简单的哥赫巴德猜想和cin优化

UVA543 Goldbach’s Conjecture - 洛谷

1622:Goldbach’s Conjecture

这题是UVA上的题,但可以在信奥网站提交。

素数筛制表,然后查表即可。因为这个猜想至今仍然没有找到一个反例,所以直接找即可。

因为数据量过大,用cin输入时需要使用优化手段,或直接用scanf。而且不能用endl

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 1;
bool vis[N];
int ans[N], pans;

void get_prim() {
	for (int i = 2; i < N; i++) {
		if (!vis[i])
			ans[++pans] = i;
		for (int j = 1; 1ull*i * ans[j] < N; j++) {
			vis[i * ans[j]] = 1;
			if (i % ans[j] == 0)
				break;
		}
	}
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);//不用这个对cin进行优化会超时
	//cout.tie(0);//这个有没有都不影响
	get_prim();
	int n;
	while (cin>>n, n) {
		for (int i = 1; i <= pans &&ans[i]<n; i++) {
			if (!vis[n - ans[i]]) {
				cout << n << " = " << ans[i] << " + " << n - ans[i] << "\n";
				break;
			}
		}
	}
	return 0;
}

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

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

相关文章

乾元通渠道商中标青海省自然灾害应急能力提升工程基层防灾项目

近日&#xff0c;乾元通渠道商中标青海省自然灾害应急能力提升工程基层防灾项目&#xff0c;乾元通作为设备厂家&#xff0c;为项目提供通信指挥类装备&#xff08;多链路聚合设备&#xff09;QYT-X1。 青岛乾元通数码科技有限公司作为国家应急产业企业&#xff0c;深耕于数据调…

openssl-aes-ctr使用openmp加速

openssl-aes-ctr使用openmp加速 openssl-aes-ctropenmp omp for openssl-aes-ctr 本文采用openssl-1.1.1w进行开发验证开发&#xff1b;因为aes-ctr加解密模式中&#xff0c;不依赖与上一个模块的加/解密的内容&#xff0c;所以对于aes-ctr加解密模式是比较适合进行并行加速的…

PHP+MySQL开发语言 在线下单订水送水小程序源码及搭建指南

随着互联网技术的不断发展&#xff0c;在线下单订水送水服务为人们所需要。分享一款 PHP 和 MySQL 搭建一个功能完善的在线订水送水小程序源码及搭建教程。这个系统将包含用户端和管理端两部分&#xff0c;用户可以在线下单、查询订单状态&#xff0c;管理员可以处理订单、管理…

计算机网络第1章(上):网络组成与三种交换方式全解析

目录 一、计算机网络的概念二、计算机网络的组成和功能2.1 计算机网络的组成2.2 计算机网络的功能 三、电路交换、报文交换、分组交换3.1 电路交换&#xff08;Circuit Switching&#xff09;3.2 报文交换&#xff08;Message Switching&#xff09;3.3 分组交换&#xff08;Pa…

Android studio进阶开发(七)---做一个完整的登录系统(前后端连接)

我们已经讲过了okhttp和登录系统的使用&#xff0c;我们今天做一个完整的登录系统&#xff0c;后端用springmybatis去做 数据库内容 -- 创建学生信息表 CREATE TABLE student_info (id SERIAL PRIMARY KEY, -- 添加自增主键name VARCHAR(255) NOT NULL,number INT NOT NULL,…

计算机网络第1章(下):网络性能指标与分层模型全面解析

目录 一、计算机网络的性能指标1.1 性能指标1&#xff1a;速率1.2 性能指标2&#xff1a;带宽1.3 性能指标3&#xff1a;吞吐量1.4 性能指标4&#xff1a;时延1.5 性能指标5&#xff1a;时延带宽积1.6 性能指标6&#xff1a;往返时延1.7 性能指标7&#xff1a;信道利用率 二、计…

恶意软件清理工具,让Mac电脑安全更简单

​你的Mac最近是不是开始表演"电子迷惑行为"&#xff1f;浏览器主页突然变成澳门赌场&#xff0c;风扇转得比直升机螺旋桨还猛......恭喜你&#xff01;可能中奖获得"恶意软件大礼包"&#xff01;别慌&#xff0c;今天就教你用恶意软件清理工具化身数字特工…

HackMyVM-Jabita

信息搜集 主机发现 ┌──(kali㉿kali)-[~] └─$ nmap -sn 192.168.43.0/24 Starting Nmap 7.95 ( https://nmap.org ) at 2025-06-01 05:20 EDT Nmap scan report for 192.168.43.1 Host is up (0.020s latency). MAC Address: C6:45:66:05:91:88 (Unknown) Nmap scan repo…

112 Gbps 及以上串行链路的有效链路均衡

通道均衡已成为当今高速串行链路的关键机制。目前有许多均衡方案&#xff0c;例如发射机加重均衡、接收机CTLE&#xff08;连续时间线性均衡器&#xff09;、FFE&#xff08;前馈均衡器&#xff09;、DFE&#xff08;判决反馈均衡器&#xff09;和FEC&#xff08;前向纠错&…

Python-13(永久存储)

创建并打开文件 open(file,mode)函数 该函数用于打开一个文件并返回对应的文件对象。 file参数指定的是文件路径和文件名&#xff0c;如果没有添加路径&#xff0c;那么默认将文件创建在python的主文件夹里面。mode参数指定的是打开的模式&#xff0c;r表示读取&#xff08;…

记录一次session安装应用recyclerview更新数据的bug

首先抛出异常日志&#xff0c;在 先说结论&#xff1a;因为session安装监听是在点击事件里面&#xff0c;所以会保留旧的对象数据 直接上代码&#xff0c;原有的逻辑是点击时执行session安装&#xff0c;并注册监听回调 private fun installApk(position: Int) {val packageIns…

大数据-274 Spark MLib - 基础介绍 机器学习算法 剪枝 后剪枝 ID3 C4.5 CART

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大模型篇章已经开始&#xff01; 目前已经更新到了第 22 篇&#xff1a;大语言模型 22 - MCP 自动操作 FigmaCursor 自动设计原型 Java篇开…

力扣面试150题--二叉树的锯齿形层序遍历

Day 56 题目描述 思路 锯齿形就是一层是从左向右&#xff0c;一层是从右向左&#xff0c;那么我们可以分析样例&#xff0c;对于第奇数层是从左向右&#xff0c;第偶数层是从右向左&#xff0c;于是可以采取一个计数器&#xff0c;采取链表方式&#xff0c;从左向右就是正常插…

如何在 CentOS / RHEL 上修改 MySQL 默认数据目录 ?

MySQL 是一个广泛使用的开源关系数据库管理系统(RDBMS)&#xff0c;为无数的 web 应用程序和服务提供支持。默认情况下&#xff0c;MySQL 将其数据存储在预定义的目录中&#xff0c;这可能并不总是适合您的需求。您可能希望将数据目录移动到另一个位置以获得更好的性能和安全性…

简历制作要精而不简

不得不说&#xff0c;不管是春招&#xff0c;还是秋招&#xff0c;我们在求职时&#xff0c;第一步便是制作一份简历。不得不承认&#xff0c;好的简历&#xff0c;就像一块敲门砖&#xff0c;能让面试官眼前一亮&#xff0c;让应聘成功的概率增添一分。 对于一个初次求职者来…

SPA-RL:通过Stepwise Progress Attribution训练LLM智能体

SPA-RL&#xff1a;通过Stepwise Progress Attribution训练LLM智能体 在大语言模型&#xff08;LLM&#xff09;驱动智能体发展的浪潮中&#xff0c;强化学习&#xff08;RL&#xff09;面临着延迟奖励这一关键挑战。本文提出的SPA-RL框架&#xff0c;通过创新的分步进度归因机…

【深度学习】9. CNN性能提升-轻量化模型专辑:SqueezeNet / MobileNet / ShuffleNet / EfficientNet

SqueezeNet / MobileNet / ShuffleNet / EfficientNet 一、背景与动机 随着深度神经网络在图像识别任务上取得巨大成功&#xff0c;它们的结构越来越深、参数越来越多。然而在移动端或嵌入式设备中&#xff1a; 存储资源有限推理计算能力弱能耗受限 因此&#xff0c;研究者…

Relational Algebra(数据库关系代数)

目录 What is an “Algebra” What is Relational Algebra? Core Relational Algebra Selection Projection Extended Projection Product&#xff08;笛卡尔积&#xff09; Theta-Join Natural Join Renaming Building Complex Expressions Sequences of Assignm…

Chorme如何对于youtube视频进行画中画背景播放?

画中画可以让你小窗播放&#xff0c;然后浏览器放后台还可以做点别的事情。 B站直接可以选择小窗播放&#xff0c;游览器最小化就可以&#xff0c;但是youtube的小窗播放游览器一切换就不显示了。 其实是因为youtube的小窗播放不是真的小窗播放。要想真的实现需要在youtube视…

017搜索之深度优先搜索——算法备赛

深度优先搜索 如果说广度优先搜索是逐层扩散&#xff0c;那深度优先搜索就是一条道走到黑。 深度优先遍历是用递归实现的&#xff0c;预定一条顺序规则&#xff08;如上下左右顺序&#xff09; &#xff0c;一直往第一个方向搜索直到走到尽头或不满足要求后返回上一个叉路口按…