《算法竞赛进阶指南》0x31质数

2024-08-29 09:52

本文主要是介绍《算法竞赛进阶指南》0x31质数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

定义

若一个正整数无法被除了1和它本身之外的任何自然数整除,则称这个数为质数(素数),反之为合数。
对于一个足够大的整数N,不超过N的质数大约有 N/lnN个,分布比较松散。

质数的判定

试除法
若一个正整数N为合数,则存在一个能整除N的数T,其中 2 ≤ T ≤ N 2\leq T \leq \sqrt{N} 2TN

因此,我们只需要扫描 [ 2 , N ] [2,\sqrt{N}] [2,N ]之间的所有整数,一次检查能否整除N,若不能则N是质数,否则N是合数。

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

质数的筛选

给定一个整数N,求出[1,n]之间所有的质数,称为质数的筛选问题。

Erathosthenes筛法
Erathosthenes筛法基于这样的思想,任意整数x的倍数都不是质数,我们可以从2开始,从小到大扫描每一个数,把他们的倍数标记为合数。当扫描到一个数时,如果没有被标记,那么就是质数。

void primes(int n)
{memset(st, 0, sizeof st);for (int i = 2; i <= n; i ++ ){if (st[i]) continue;prime[cnt ++ ] = i;for (int j = i; j <= n / i; j ++ ) st[i * j] = 1;}
}

时间复杂度为 O ( n l o g l o g n ) = n ∗ ( 1 / 2 + 1 / 3 + 1 / 5 + 1 / 7 + . . . + 1 / n ) = n l o g l o g n 时间复杂度为O(nloglogn)=n*(1/2+1/3+1/5+1/7+...+1/n)=nloglogn 时间复杂度为O(nloglogn)=n(1/2+1/3+1/5+1/7+...+1/n)=nloglogn

线性筛法
线性筛法通过“从大到小累积质因子”的方式标记每个合数。
1.依次考虑[2,n]之间的每一个数i。
2.若st[i]=0,说明i是质数,保存下来。
3.扫描每个质数p,令v[i*p]=p.也就是在i的基础上累计一个质因子p。因为p<=i的最小质因子,所以p就是合数i*p的最小质因子。

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

每个合数i*p只会被最小质因子p筛一次,时间复杂度为O(n)。

质因数分解

任何一个大于1的正整数都能唯一分解成有限个质数的乘积,可写作:
N = p 1 c 1 p 2 c 2 . . . p m c m N=p_1^{c1}p_2^{c2}...p_m^{cm} N=p1c1p2c2...pmcm
其中ci为正整数,pi为质数,且 p 1 < p 2 < . . . < p n p_1 < p_2 < ... <pn p1<p2<...<pn

试除法

void divide(int n)
{m = 0;for (int i = 2; i <= sqrt(n); i ++ ){if (n % 2 == 0){p[ ++ m] = i, c[m] = 0;while (n % i == 0) n /= i, c[m] ++ ;}}if (n > 1) p[ ++ m] = 1, c[m] = 1;for (int i = 1; i <= m; i ++ )cout << p[i] << '^' << c[i] << endl;
}

时间复杂度为 O ( n ) O(\sqrt{n}) O(n )

例题

acwing196.质数距离

如果直接使用线性筛求出[2,r]之间的所有质数的话时间复杂度为T*10^9,显然会超时,我们考虑使用线性筛求出 [ 2 , r ] [2,\sqrt{r}] [2,r ]之间所有的素数,对于每个素数,把[l,r]中能被该质数整除的数标记。

时间复杂度分为两部分,线性筛的时间复杂度加上求区间合数的时间复杂度。
前者时间复杂度为 O ( r ) O(\sqrt{r}) O(r )
后者时间复杂度为 ( r − l ) / 2 + ( r − l ) / 3 + ( r − l ) / 5 + . . . + ( r − l ) / r = O ( ( r − l ) ∗ ( l o g l o g n ) ) (r-l)/2+(r-l)/3+(r-l)/5+...+(r-l)/\sqrt{r}=O((r-l)*(loglog\sqrt{n})) (rl)/2+(rl)/3+(rl)/5+...+(rl)/r =O((rl)(loglogn ))
总和为 O ( T ∗ ( r + ( r − l ) ∗ ( l o g l o g n ) ) ) O(T*(\sqrt{r}+(r-l)*(loglog\sqrt{n}))) O(T(r +(rl)(loglogn )))

#include <iostream>
#include <cstring>
using namespace std;
#define N 1000010
typedef long long ll;
bool st[N];
int prime[N];
int cnt = 0;
void init(int n)
{memset(st, 0, sizeof st);cnt = 0;for (int i = 2; i <= n; i ++ ){if (!st[i]) prime[cnt ++ ] = i;for (int j = 0; i * prime[j] <= n; j ++ ){st[i * prime[j]] = true;if (i % prime[j] == 0) break;}}
}
int main()
{int l, r;while (cin >> l >> r){init(500000);memset(st, 0, sizeof st);for (int i = 0; i < cnt; i ++ ){ll p = prime[i];for (ll j = max(2 * p, (l - 1 + p) / p * p); j <= r; j += p)st[j - l] = true;}cnt = 0;for (int i = 0; i <= r - l; i ++ ){if (!st[i] && i + l >= 2) prime[cnt ++ ]  = i + l;}if (cnt < 2) puts("There are no adjacent primes.");else{int minp = 0, maxp = 0;for(int i = 0; i < cnt - 1; i ++ ){int d = prime[i + 1] - prime[i];if (d < prime[minp + 1] - prime[minp]) minp = i;if (d > prime[maxp + 1] - prime[maxp]) maxp = i;}printf("%d,%d are closest, %d,%d are most distant.\n",prime[minp], prime[minp + 1], prime[maxp], prime[maxp + 1]);}}return 0;
}

acwing197.阶乘分解
首先排除先求出阶乘再用试除法分解质因数的方法。
再排除对于1-n每一个整数分解质因数,最后进行整合的方法,因为这样的时间复杂度为 O ( n n ) O(n\sqrt{n}) O(nn ),依然会超时。
考虑枚举质数,因为N!的阶乘的质因数肯定不会大于N,所以找丛2到N的所有质数p。
对于每一个p^k,求其会贡献多少个质数p的数量,即
⌊ N / p ⌋ + ⌊ N / p 2 ⌋ + ⌊ N / p 3 ⌋ + . . . + ⌊ N / p k ⌋ \lfloor N/p \rfloor+\lfloor N/p^2 \rfloor+\lfloor N/p^3 \rfloor+...+\lfloor N/p^k \rfloor N/p+N/p2+N/p3+...+N/pk
一共有 l o g p n log_p^n logpn项,可以以O(1)的时间求出每一项的值。又因为前n个数中质数数量为n/logn,所以 l o g 2 n + l o g 3 n + l o g 5 n . . . < l o g 2 n ∗ n / l o g 2 n = n log_2^n+log_3^n+log_5^n...<log_2^n *n/log_2^n = n log2n+log3n+log5n...<log2nn/log2n=n
所以总体时间复杂度为 O ( n ) O(n) O(n)

#include <iostream>
using namespace std;
#define N 1000010
bool st[N];
int prime[N];
int n, cnt = 0;
typedef long long ll;
void init(int n)
{for (int i = 2; i <= n; i ++ ){if(!st[i]) prime[cnt ++ ] = i;for (int j = 0; prime[j] * i <= n; j ++ ){st[i * prime[j]] =true;if (i % prime[j] == 0)break;}}
}
int main()
{cin >> n;init(n);for (int i = 0; i < cnt; i ++ ){int p = prime[i];int s = 0;for (ll j = p; j <= n; j *= p)s += n / j;printf("%d %d\n", p, s);}return 0;
}

这篇关于《算法竞赛进阶指南》0x31质数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1117527

相关文章

SpringBoot整合 Quartz实现定时推送实战指南

《SpringBoot整合Quartz实现定时推送实战指南》文章介绍了SpringBoot中使用Quartz动态定时任务和任务持久化实现多条不确定结束时间并提前N分钟推送的方案,本文结合实例代码给大... 目录前言一、Quartz 是什么?1、核心定位:解决什么问题?2、Quartz 核心组件二、使用步骤1

在C#中分离饼图的某个区域的操作指南

《在C#中分离饼图的某个区域的操作指南》在处理Excel饼图时,我们可能需要将饼图的各个部分分离出来,以使它们更加醒目,Spire.XLS提供了Series.DataFormat.Percent属性,... 目录引言如何设置饼图各分片之间分离宽度的代码示例:从整个饼图中分离单个分片的代码示例:引言在处理

Python列表的创建与删除的操作指南

《Python列表的创建与删除的操作指南》列表(list)是Python中最常用、最灵活的内置数据结构之一,它支持动态扩容、混合类型、嵌套结构,几乎无处不在,但你真的会创建和删除列表吗,本文给大家介绍... 目录一、前言二、列表的创建方式1. 字面量语法(最常用)2. 使用list()构造器3. 列表推导式

Python数据验证神器Pydantic库的使用和实践中的避坑指南

《Python数据验证神器Pydantic库的使用和实践中的避坑指南》Pydantic是一个用于数据验证和设置的库,可以显著简化API接口开发,文章通过一个实际案例,展示了Pydantic如何在生产环... 目录1️⃣ 崩溃时刻:当你的API接口又双叒崩了!2️⃣ 神兵天降:3行代码解决验证难题3️⃣ 深度

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Java 队列Queue从原理到实战指南

《Java队列Queue从原理到实战指南》本文介绍了Java中队列(Queue)的底层实现、常见方法及其区别,通过LinkedList和ArrayDeque的实现,以及循环队列的概念,展示了如何高效... 目录一、队列的认识队列的底层与集合框架常见的队列方法插入元素方法对比(add和offer)移除元素方法

Spring Boot基于 JWT 优化 Spring Security 无状态登录实战指南

《SpringBoot基于JWT优化SpringSecurity无状态登录实战指南》本文介绍如何使用JWT优化SpringSecurity实现无状态登录,提高接口安全性,并通过实际操作步骤... 目录Spring Boot 实战:基于 JWT 优化 Spring Security 无状态登录一、先搞懂:为什

Nginx概念、架构、配置与虚拟主机实战操作指南

《Nginx概念、架构、配置与虚拟主机实战操作指南》Nginx是一个高性能的HTTP服务器、反向代理服务器、负载均衡器和IMAP/POP3/SMTP代理服务器,它支持高并发连接,资源占用低,功能全面且... 目录Nginx 深度解析:概念、架构、配置与虚拟主机实战一、Nginx 的概念二、Nginx 的特点

C#实现插入与删除Word文档目录的完整指南

《C#实现插入与删除Word文档目录的完整指南》在日常的办公自动化或文档处理场景中,Word文档的目录扮演着至关重要的角色,本文将深入探讨如何利用强大的第三方库Spire.Docfor.NET,在C#... 目录Spire.Doc for .NET 库:Word 文档处理利器自动化生成:C# 插入 Word

MySQL 数据库进阶之SQL 数据操作与子查询操作大全

《MySQL数据库进阶之SQL数据操作与子查询操作大全》本文详细介绍了SQL中的子查询、数据添加(INSERT)、数据修改(UPDATE)和数据删除(DELETE、TRUNCATE、DROP)操作... 目录一、子查询:嵌套在查询中的查询1.1 子查询的基本语法1.2 子查询的实战示例二、数据添加:INSE