【算法学习笔记】32:筛法求解欧拉函数

server/2025/1/16 9:11:51/

上节学习的是求一个数 n n n欧拉函数,因为用的试除法,所以时间复杂度是 O ( n ) O(\sqrt{n}) O(n ),如果要求 m m m个数的欧拉函数,那么就会花 O ( m n ) O(m \sqrt{n}) O(mn )的时间。如果是求连续一批数的欧拉函数,可以用筛法进行优化。

筛法求欧拉函数原理

线性筛质数时可以顺便把每个数的欧拉函数筛出来。根据线性筛过程,一个数要么是质数被pick出来,要么是合数被筛掉,一共有这样三个地方:

  1. 从筛子(st数组)里发现 i i i是一个质数
  2. 合数 p r i m e s [ j ] ∗ i primes[j] * i primes[j]i被筛掉,其中质数 p r i m e s [ j ] primes[j] primes[j]同时也是 i i i的质因子(按照线性筛,也一定是最小质因子)
  3. 合数 p r i m e s [ j ] ∗ i primes[j] * i primes[j]i被筛掉,其中质数 p r i m e s [ j ] primes[j] primes[j]不是 i i i的质因子(仅仅是 p r i m e s [ j ] ∗ i primes[j] * i primes[j]i的最小质因子)

三种情况合起来就不多不少地包含了从 1 1 1 n n n的所有数字。

  • 对于情况1,质数 i i i欧拉函数根据定义就是除了 i i i之外的那 i − 1 i - 1 i1个数,因为它们一定都和 i i i互质,所以 ϕ ( i ) = i − 1 \phi(i) = i - 1 ϕ(i)=i1
  • 对于情况2,因为 p r i m e s [ j ] primes[j] primes[j]也是 i i i的质因子,根据欧拉公式,除了第一项外剩下那些用1减的项,都只和质因子有关,和质因子的指数无关,因此相比 ϕ ( i ) \phi(i) ϕ(i) ϕ ( p r i m e s [ j ] ∗ i ) \phi(primes[j] * i) ϕ(primes[j]i)只有第一项从 i i i变成了 p r i m e s [ j ] ∗ i primes[j] * i primes[j]i
  • 对于情况3,因为 p r i m e s [ j ] primes[j] primes[j]是一个质数而且和 i i i互质,因此 ϕ ( p r i m e s [ j ] ∗ i ) \phi(primes[j] * i) ϕ(primes[j]i)的公式里,除了第一项要变成 p r i m e s [ j ] ∗ i primes[j] * i primes[j]i,还因为添加了一个新的质数 p r i m e s [ j ] primes[j] primes[j]所以要乘以一个 1 − 1 p r i m e s [ j ] 1 - \frac{1}{primes[j]} 1primes[j]1,所以总共要乘以 p r i m e s [ j ] − 1 primes[j] - 1 primes[j]1

例题:AcWing 874. 筛法求欧拉函数

只要利用线性筛的模板和上面的结论,在三个地方填空即可。

#include <iostream>using namespace std;typedef unsigned long long ULL;const int N = 1e6 + 10;int primes[N], cnt;
bool st[N];
int eulars[N];int main() {int n; cin >> n;eulars[1] = 1;for (int i = 2; i <= n; i ++ ) {if (!st[i]) {primes[cnt ++ ] = i;// i是质数,从1到i-1都和i互质eulars[i] = i - 1;}for (int j = 0; primes[j] * i <= n; j ++ ) {st[primes[j] * i] = true;if (i % primes[j] == 0) {// primes[j]是i的质因子,欧拉公式里只要变第一项eulars[primes[j] * i] = eulars[i] * primes[j];break;}// primes[j]不是i的质因子,欧拉公式里要变第一项和(1-1/primes[j])那项eulars[primes[j] * i] = eulars[i] * (primes[j] - 1);}}ULL res = 0;for (int i = 1; i <= n; i ++ ) {res += eulars[i];}cout << res << endl;return 0;
}

http://www.ppmy.cn/server/158785.html

相关文章

Windows图形界面(GUI)-QT-C/C++ - Qt图形绘制详解

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 Qt绘图基础 QPainter概述 基本工作流程 绘图事件系统 paintEvent事件 重绘机制 文字绘制技术 基本文字绘制 ​编辑 高级文字效果 基本图形绘制 线条绘制 ​编辑 形状绘制 …

Flink (五) :DataStream API (二)

1. Transformations 用户通过算子能将一个或多个 DataStream 转换成新的 DataStream&#xff0c;在应用程序中可以将多个数据转换算子合并成一个复杂的数据流拓扑。 1.1 Map DataStream → DataStream: 输入一个元素同时输出一个元素。下面是将输入流中元素数值加倍的 map f…

lanqiaoOJ 3333:肖恩的排序 ← 双指针+排序(从大到小)

【题目来源】https://www.lanqiao.cn/problems/3333/learning/【题目描述】 肖恩提出了一种新的排序方法。 该排序方法需要一个标准数组 B 和一个待排序数组 A。在确保对于所有位置 i 都有 A[i]>B[i] 的前提下&#xff0c;肖恩可以自由选择 A 数组的排序结果。请计算按照这种…

1.3 k8s-上部署第一个应用程序

本节重点总结&#xff1a; 部署nginx Deploymentkubectl 基础命令 apply对资源进行配置get 查看资源describe 查看资源详细信息logs 查看pod中的日志exec 在pod中的容器环境内执行命令 Deployment 基本概念 Deployment 译名为 部署。在k8s中&#xff0c;通过发布 Deployment…

excel仅复制可见单元格,仅复制筛选后内容

背景 我们经常需要将内容分给不同的人&#xff0c;做完后需要合并 遇到情况如下 那是因为直接选择了整列&#xff0c;当然不可以了。 下面提供几种方法&#xff0c;应该都可以 直接选中要复制区域然后复制&#xff0c;不要选中最上面的列alt;选中可见单元格正常复制&#xff…

MATLAB学习笔记目录

MATLAB学习笔记-生成纯音并保存-CSDN博客 MATLAB学习笔记-各种格式之间的转换 - 知乎 MATLAB学习笔记-胞组&#xff08;cell array&#xff09;转换为矩阵&#xff0c;cell2mat_matlab如何把元胞数组改为矩阵-CSDN博客MATLAB学习笔记-判断数组、结构体、数值、字符串是否相同…

NLP自然语言处理分词模块PaddleNLP

自然语言处理(NLP)是人工智能的重要组成部分,主要用于处理和分析自然语言数据。在中文的自然语言处理中,分词是关键的一环。分词是指将一段连续的文字切分成一个个单独的词语或短语,以便于进一步的分析和处理。 PaddleNLP 是基于飞桨(PaddlePaddle)深度学习框架的自然语…

【React】脚手架进阶

目录 暴露webpack配置package.json的变化修改webpack.config.js配置less修改域名、端口号浏览器兼容处理处理跨域 暴露webpack配置 react-scripts对脚手架中的打包命令进行封装&#xff0c;如何暴露这些打包配置呢&#xff1f;上篇写到在package.json中的scripts配置项中有eje…