素数判定方法详解:从基础试除法到优化策略
素数是只能被1和自身整除的正整数。素数的判定是数论中的基础问题,也是算法竞赛中的常见考点。
一、知识点
-
素数的定义:
素数(质数)是大于1的自然数,且只能被1和自身整除。 -
试除法:
通过遍历从2到sqrt(n)的所有整数,判断是否能整除n。如果能整除,则n不是素数。 -
试除法的优化:
-
优化1:将试除范围从[2, n-1]缩小到[2, sqrt(n)]。
-
优化2:仅用[2, sqrt(n)]内的素数试除,避免用合数试除。
-
-
时间复杂度:
-
未优化的试除法:O(n)。
-
优化后的试除法:O(sqrt(n))。
-
二、试除法及其优化
1. 基础试除法
-
原理:遍历从2到sqrt(n)的所有整数,检查是否能整除n。
-
代码实现:
bool isPrime(long long n) {if (n <= 1) return false; // 1不是素数for (long long i = 2; i <= sqrt(n); i++) {if (n % i == 0) return false; // 能整除,不是素数}return true; // 是素数 } -
说明:
-
sqrt(n):只需遍历到sqrt(n),因为如果n有大于sqrt(n)的因子,必然有小于sqrt(n)的因子。 -
时间复杂度:O(sqrt(n))。
-
2. 试除法的第一次优化
-
原理:仅用[2, sqrt(n)]内的素数试除,避免用合数试除。
-
实现步骤:
-
预先生成[2, sqrt(n)]内的所有素数(如用筛法)。
-
用这些素数试除n。
-
-
代码实现:
bool isPrimeOptimized(long long n, const vector<long long>& primes) {if (n <= 1) return false; // 1不是素数for (long long p : primes) {if (p * p > n) break; // 超过sqrt(n),停止if (n % p == 0) return false; // 能整除,不是素数}return true; // 是素数 } -
说明:
-
primes:预先生成的素数列表(如用埃氏筛法生成)。 -
时间复杂度:O(sqrt(n)/logn),因为素数密度约为logn。
-
3. 试除法的第二次优化
-
原理:结合筛法,动态生成素数列表,避免预先生成。
-
实现步骤:
-
使用筛法(如埃氏筛法)动态生成[2, sqrt(n)]内的素数。
-
用这些素数试除n。
-
-
代码实现:
vector<long long> generatePrimes(long long limit) {vector<bool> isPrime(limit + 1, true);vector<long long> primes;for (long long i = 2; i <= limit; i++) {if (isPrime[i]) {primes.push_back(i);for (long long j = i * i; j <= limit; j += i) {isPrime[j] = false;}}}return primes; }bool isPrimeOptimized2(long long n) {if (n <= 1) return false; // 1不是素数long long limit = sqrt(n);vector<long long> primes = generatePrimes(limit);return isPrimeOptimized(n, primes); } -
说明:
-
generatePrimes:生成[2, sqrt(n)]内的素数列表。 -
时间复杂度:O(sqrt(n) log logn)(筛法复杂度)。
-
三、代码说明
-
基础试除法:
-
适用于小规模数据(n≤10^12)。
-
实现简单,但效率较低。
-
-
第一次优化:
-
通过预先生成素数列表,减少试除次数。
-
适用于需要多次判断素数的场景。
-
-
第二次优化:
-
动态生成素数列表,避免预先生成。
-
适用于单次判断素数且n较大的场景。
-
四、例题解析
P1036 [NOIP 2002 普及组] 选数 - 洛谷

算法代码:
#include<bits/stdc++.h> // 包含所有标准库头文件
using namespace std; // 使用标准命名空间int n, k; // n: 数组长度, k: 需要选择的元素个数
int a[20]; // 存储输入的数组
int ans; // 记录满足条件的组合数// 判断一个数是否为素数
bool is_prime(int s) {if (s <= 1) { // 1及以下的数不是素数return false;}for (int i = 2; i <= sqrt(s); i++) { // 遍历2到sqrt(s)if (s % i == 0) { // 如果s能被i整除,说明s不是素数return false;}}return true; // 否则s是素数
}// 深度优先搜索(DFS)函数
// cnt: 当前已选择的元素个数
// sum: 当前已选择元素的和
// p: 当前选择的起始位置
void dfs(int cnt, int sum, int p) {if (cnt == k) { // 如果已经选择了k个元素if (is_prime(sum)) { // 判断这些元素的和是否为素数ans++; // 如果是素数,答案加1}return; // 返回上一层递归}for (int i = p; i < n; i++) { // 从位置p开始选择元素dfs(cnt + 1, sum + a[i], i + 1); // 递归选择下一个元素}
}int main() {cin >> n >> k; // 输入数组长度n和需要选择的元素个数kfor (int i = 0; i < n; i++) { // 输入数组元素cin >> a[i];}dfs(0, 0, 0); // 调用DFS函数,初始状态:已选0个元素,和为0,起始位置为0cout << ans; // 输出满足条件的组合数return 0; // 程序结束
}
1. 问题描述
-
输入:一个长度为
n的数组a,以及一个整数k。 -
目标:从数组
a中选择k个元素,使得这些元素的和为素数。统计所有满足条件的组合数。
2. 设计思路
(1)核心问题分解
-
子问题1:如何判断一个数是否为素数?
-
子问题2:如何从数组中选择
k个元素,并计算它们的和? -
子问题3:如何统计所有满足条件的组合数?
(2)解决子问题1:素数判断
-
方法:使用试除法。
-
遍历从2到sqrt(n)的所有整数,检查是否能整除
n。 -
如果能整除,则
n不是素数;否则,n是素数。
-
-
代码实现:
bool is_prime(int s) {if (s <= 1) return false; // 1及以下的数不是素数for (int i = 2; i <= sqrt(s); i++) {if (s % i == 0) return false; // 能整除,不是素数}return true; // 是素数 }
(3)解决子问题2:选择k个元素并计算和
-
方法:使用深度优先搜索(DFS)遍历所有可能的组合。
-
从数组中选择
k个元素,确保不重复选择。 -
在DFS过程中,记录当前已选择的元素个数、当前和以及选择的起始位置。
-
-
代码实现:
void dfs(int cnt, int sum, int p) {if (cnt == k) { // 已选择k个元素if (is_prime(sum)) ans++; // 如果和为素数,答案加1return;}for (int i = p; i < n; i++) { // 从位置p开始选择dfs(cnt + 1, sum + a[i], i + 1); // 递归选择下一个元素} }
(4)解决子问题3:统计满足条件的组合数
-
方法:在DFS过程中,每当找到一个满足条件的组合(和为素数),就将计数器
ans加1。 -
代码实现:
int ans = 0; // 初始化计数器 dfs(0, 0, 0); // 调用DFS函数 cout << ans; // 输出结果
3. 代码实现步骤
(1)输入部分
-
读取数组长度
n和需要选择的元素个数k。 -
读取数组
a的元素。cin >> n >> k; for (int i = 0; i < n; i++) {cin >> a[i]; }
(2)DFS函数
-
参数说明:
-
cnt:当前已选择的元素个数。 -
sum:当前已选择元素的和。 -
p:当前选择的起始位置(避免重复选择)。
-
-
递归终止条件:
-
当
cnt == k时,检查sum是否为素数。如果是,则ans++。
-
-
递归过程:
-
从位置
p开始,依次选择数组中的元素,并递归调用DFS。void dfs(int cnt, int sum, int p) {if (cnt == k) {if (is_prime(sum)) ans++;return;}for (int i = p; i < n; i++) {dfs(cnt + 1, sum + a[i], i + 1);} }
-
(3)输出结果
-
调用DFS函数后,输出满足条件的组合数
ans。dfs(0, 0, 0); cout << ans;
4. 时间复杂度分析
-
is_prime函数:O(sqrt(n))。
-
DFS函数:O(C(n,k)),其中C(n,k)是从
n个元素中选择k个元素的组合数。 -
总时间复杂度:O(C(n,k)×sqrt(n))。
5. 优化建议
-
剪枝优化:在DFS过程中,如果当前和
sum已经大于某个阈值,可以提前终止递归。 -
素数预处理:如果需要多次判断素数,可以预先生成一个素数表,减少重复计算。
相关文章:
素数判定方法详解:从基础试除法到优化策略
素数是只能被1和自身整除的正整数。素数的判定是数论中的基础问题,也是算法竞赛中的常见考点。 一、知识点 素数的定义: 素数(质数)是大于1的自然数,且只能被1和自身整除。 试除法: 通过遍历从2到sqrt(n)…...
BFS,DFS带图详解+蓝桥杯算法题+经典例题
1.BFS和DFS的定义与实现方式 1.1 深度优先搜索(DFS) 基本概念:DFS 是一种用于遍历或搜索图或树的算法。它从起始节点开始,沿着一条路径尽可能深地探索下去,直到无法继续或者达到目标节点,然后回溯到上一个…...
「清华大学、北京大学」DeepSeek 课件PPT专栏
你要的 这里都打包好啦,快快收藏起来! 名称 链接 团队简介 类型 DeepSeek——从入门到精通 1️⃣ DeepSeek从入门到精通「清华团队」 清华大学新闻与传播学院 新媒体研究中心 元宇宙文化实验室 PPT课件 DeepSeek如何赋能职场应用? ——从提示语…...
如何在 Github 上获得 1000 star?
作为程序员,Github 是第一个绕不开的网站。我们每天都在上面享受着开源带来的便利,我相信很多同学也想自己做一个开源项目,从而获得大家的关注。然而,理想很丰满,现实却是开发了很久的项目仍然无人问津。 最近&#x…...
on-policy对比off-policy
目录 持续更新。。。 on-policy与off-policy的定义 Q-learning属于on-policy算法还是off-policy算法? 为什么off-policy适用于从离线经验或多种探索策略中学习,明明 On-policy 也可以基于探索学习的啊? 重要性权重方法 off-policy方法可…...
标准卡尔曼滤波
1.状态转移方程和观测方程 状态转移方程 x k A x k − 1 B u k w k x_k A x_{k-1} Bu_k w_k xkAxk−1Bukwk x k x_k xk:k时刻的 状态向量,理论上的真实状态。 x k − 1 x_{k-1} xk−1:k-1时刻的 状态向量,理论…...
主流区块链
文章目录 主流链1. Solana特点:适用场景:工具链: 2. Binance Smart Chain (BSC)特点:适用场景:工具链: 3. Avalanche特点:适用场景:工具链: 4. Polkadot特点:…...
pytorch中有哪些损失函数
L1Loss 计算预测值 ypred 和真实值 ytrue 之间的平均绝对误差(MAE),公式为 L ( y p r e d , y t r u e ) 1 n ∑ i 1 n ∣ y p r e d i − y t r u e i ∣ L(y_{pred},y_{true})\frac1n\sum^n_{i1}|y^i_{pred}-y^i_{true}| L(ypred,ytru…...
【设计模式有哪些】
一、创建型模式(Creation Patterns) 1. 单例模式(Singleton) 核心思想:保证一个类仅有一个实例,并提供全局访问点。实现方式:public class Singleton {// 1. 私有静态实例,volatil…...
基于SpringBoot+Vue的幼儿园管理系统+LW示例参考
1.项目介绍 系统角色:管理员、教师、普通用户功能模块:用户管理、教师管理、班级管理、幼儿信息管理、会议记录管理、待办事项、职工考核、请假信息、缴费信息、体检管理、资源管理、原料管理、菜品信息管理等技术选型:SpringBoot࿰…...
默认参数 d = {} 的陷阱
默认参数 d {} 的陷阱 问题需求思路代码实现默认参数d {}的陷阱解决办法1、在函数外为每个字符串创建空字典统计词频2、函数改为每次调用时创建新字典,避免数据污染 举一反三 问题需求 统计两个字符串的中文词语出现次数 思路 先使用jieba库分词功能处理字符串…...
Python 常用内建模块-argparse
目录 argparse 小结 argparse 在命令行程序中,经常需要获取命令行参数。Python内置的sys.argv保存了完整的参数列表,我们可以从中解析出需要的参数: # copy.py import sys print(sys.argv) source sys.argv[1] target sys.argv[2] # TOD…...
案例5_3: 6位数码管静态显示
文章目录 文章介绍效果图仿真图复习知识:代码思考 文章介绍 第5章 学习数码管,使用6位数码管进行静态显示 效果图 仿真图 新建一个干净的5_3文件夹,用于存放新画的仿真图 除单片机最小系统外,新增3个元器件,分别是&…...
Profinet转Modbus RTU/TCP以太网通讯处理器
Profinet转Modbus RTU/TCP以太网通讯处理器 在当今的工业自动化领域,各种通讯协议和标准层出不穷。 其中,Profinet和Modbus作为两种广泛应用的通讯协议,分别在不同的应用场景中发挥着重要作用。 然而,当需要将这两种协议进行转换…...
3倍训练速度+40%显存节省!Mamba+Transformer 仅用一半时间,性能提升80%!
在人工智能领域,Mamba与Transformer的结合正在成为研究热点,为自然语言处理和多模态任务带来新的突破。 最新研究表明,通过将Mamba架构与Transformer的强大编码能力相结合,模型在处理复杂的多模态数据时的效率提升了50%ÿ…...
春秋云境刷题1
CVE-2022-29464 靶标介绍: WSO2文件上传漏洞(CVE-2022-29464)是Orange Tsai发现的WSO2上的严重漏洞。该漏洞是一种未经身份验证的无限制任意文件上传,允许未经身份验证的攻击者通过上传恶意JSP文件在WSO2服务器上获得RCE。 Git…...
台式机电脑组装---电源
台式机电脑组装—电源 22 33 主板供电是聚集了12V,5V,3.3V的24pin CPU供电的话主要是12V的44pin供电 44pin合并之后,就是8pin 55 SATA硬盘会使用饼io口取电,从电源获取12v,5v,3.3v的电 33...
10-BST(二叉树)-建立二叉搜索树,并进行前中后遍历
题目 来源 3540. 二叉搜索树 - AcWing题库 思路 建立二叉搜索树(注意传参时用到了引用,可以直接对root进行修改),同时进行递归遍历;遍历可以分前中后三种写,也可以用标志来代替合在一起。其余详见代码。…...
蓝桥杯备考:贪心问题之淘淘摘苹果
这是淘淘摘苹果普通版,很可爱的一道题,我们不多陈述,直接上代码 #include <iostream> using namespace std; const int N 15; int a[N]; int main() {for(int i 1;i<10;i){cin >> a[i];}int x;cin >> x;x30;int cnt …...
VSTO(C#)Excel开发 系列目录 含源码发布
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...
在 Ubuntu 下通过 Docker 部署 Nginx+PHP-FPM 服务器
引言 大家好,今天我们来聊聊如何在 Ubuntu 下通过 Docker 部署 Nginx 和 PHP-FPM 服务器。Docker 是一个开源的容器化平台,可以轻松地打包、分发和管理应用程序。而 Nginx 是一个高性能的 HTTP 服务器和反向代理服务器,PHP-FPM 则是 PHP 的一…...
Git使用和原理(3)
1.远程操作 1.1分布式版本控制系统 我们⽬前所说的所有内容(⼯作区,暂存区,版本库等等),都是在本地!也就是在你的笔记本或者 计算机上。⽽我们的 Git 其实是分布式版本控制系统!什么意思呢&a…...
【ELK】节省存储 之 压缩存储方式调整
目录 集群版本: 7.17.6 解释几个概念: 段(Segment) 合并(Merge) 索引设置: 压缩方式(index.codec): 测试设置前提条件 对比 在创建的时候指定压缩类型(index.codec) 对比 在…...
导出的使用
在web开发中,导出是很常见的一个功能,当我进行个人项目练习的时候,导出的时候无法控制列宽以及居中样式,后续发现导出插件无法进行修改,整个插件较为简便易懂的同时,对于EX的控制较为简陋,很多东…...
博客图床 VsCode + PigGo + 阿里云OSS
关键字 写博客,图床,VsCode,PigGo,阿里云OSS 背景环境 我想把我在本地写的markdown文档直接搬到CSDN上和博客园上,但是图片上传遇到了问题。我需要手动到不同平台上传文件,非常耗费时间和经历。 为了解决…...
鸿蒙开源硬件:重构万物智联生态的底层基座与未来机遇
一、从生态裂变到产业重构:开源鸿蒙的崛起之路 自 2020 年开源至今,OpenHarmony 社区以惊人的发展速度重塑智能终端操作系统格局。数据显示,其代码量已从初始的 700 万行激增至 1.2 亿行,汇聚超 8200 名开发者及 70 余家核心共建…...
C++之list类及模拟实现
目录 list的介绍 list的模拟实现 定义节点 有关遍历的重载运算符 list的操作实现 (1)构造函数 (2)拷贝构造函数 (3)赋值运算符重载函数 (4)析构函数和clear成员函数 (5)尾…...
SwinTransformer 改进:添加DoubleAttention模块提升上下文语义提取能力
目录 1. DoubleAttention模块 2. SwinTransformer + DoubleAttention 3. 完整代码 Tips:融入模块后的网络经过测试,可以直接使用,设置好输入和输出的图片维度即可 1. DoubleAttention模块 DoubleAttention 是一种用于计算机视觉任务的注意力机制,旨在通过双重注意力机制…...
在Electron中实现实时下载进度显示的完整指南
在开发Electron应用时,提供良好的用户体验至关重要,尤其是在下载大文件时。用户需要知道下载进度、预计完成时间以及当前下载速度。本文将详细介绍如何在Electron应用中实现实时下载进度显示功能,从主进程到渲染进程的完整流程。 技术栈是ele…...
java生成一个可以下载的word文件
在 Java 里,你能够借助 Apache POI 库来生成 Word 文件,并且实现文件下载功能。下面为你详细介绍实现步骤和示例代码。 1. 添加依赖 若使用 Maven 项目,需在 pom.xml 里添加 Apache POI 的依赖: <dependencies><depen…...
