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

ops/2025/1/17 20:43:39/

上节学习的是求一个数 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/ops/150913.html

相关文章

STM32网络通讯之CubeMX实现LWIP项目设计(十五)

STM32F407 系列文章 - ETH-LWIP-CubeMX&#xff08;十五&#xff09; 目录 前言 一、软件设计 二、CubeMX实现 1.配置前准备 2.CubeMX配置 1.ETH模块配置 2.时钟模块配置 3.中断模块配置 4.RCC及SYS配置 5.LWIP模块配置 3.生成代码 1.main文件 2.用户层源文件 3.…

解锁未来情感科技:AI 机器人 Ropet 搭载的前沿智能黑科技

2025年的国际消费电子产品展览会&#xff08;CES&#xff09;上&#xff0c;一只可爱的“毛绒玩具”成了全场焦点。 当然&#xff0c;这并不是一个单纯的玩偶&#xff0c;而是和《超能陆战队》的大白一样温暖的陪伴机器人。 相信有很多人和小编一样&#xff0c;当年看完《超能…

【微服务justsoso-cloud系列】目录

【微服务justsoso-cloud系列】目录 1.vagrantvirtualbox实现centos7安装 2.centos7安装jdk17教程 3.Linux安装Docker教程&#xff08;详解&#xff09; 4.Linux安装git 5.zerotier搭建虚拟局域网&#xff0c;自建planet

Linux 文件权限详解

目录 前言 查看文件权限 修改文件权限 符号方式 数字方式 前言 Linux 文件权限是系统中非常重要的概念之一&#xff0c;用于控制对文件和目录的访问。权限分为读&#xff08;Read&#xff09;、写&#xff08;Write&#xff09;、执行&#xff08;Execute&#xff09;三个…

usb通过hdc连接鸿蒙next的常用指令

参考官方 注册报名https://www.hiascend.com/developer/activities/details/44de441ef599450596131c8cb52f7f8c/signup?channelCodeS1&recommended496144 hdc-调试命令-调测调优-系统 - 华为HarmonyOS开发者https://developer.huawei.com/consumer/cn/doc/harmonyos-guid…

【机器学习:十五、神经网络的编译和训练】

1. TensorFlow实现代码 TensorFlow 是深度学习中最为广泛使用的框架之一&#xff0c;提供了灵活的接口来构建、编译和训练神经网络。以下是实现神经网络的一个完整代码示例&#xff0c;以“手写数字识别”为例&#xff1a; import tensorflow as tf from tensorflow.keras im…

util层注入service

简介背景 在 Java 或 Spring 框架中&#xff0c;util 层通常用于存放工具类或辅助类&#xff0c;而 service 层则通常包含核心业务逻辑。在一些情况下&#xff0c;可能需要将 service 层注入到 util 层中&#xff0c;以便在工具类中调用某些业务逻辑。虽然这种做法并不是最常见…

Spring Boot 下的Swagger 3.0 与 Swagger 2.0 的详细对比

先说结论&#xff1a; Swgger 3.0 与Swagger 2.0 区别很大&#xff0c;Swagger3.0用了最新的注释实现更强大的功能&#xff0c;同时使得代码更优雅。 就个人而言&#xff0c;如果新项目推荐使用Swgger 3.0&#xff0c;对于工具而言新的一定比旧的好&#xff1b;对接于旧项目原…