当前位置: 首页 > article >正文

【数论】—— 欧拉函数

欧拉函数

在做关于素数的题目时经常需要用到关于欧拉函数的知识,并且求法相似,所以建议先看我的素数 blog。

求单个数的欧拉函数

定义

对于任意正整数 n n n,欧拉函数 φ ( n ) \varphi(n) φ(n) 表示在不大于 n n n 的正整数中与 n n n 互素的数的个数。

举几个例子:

  • φ ( 1 ) = 1 \varphi(1)=1 φ(1)=1,即 1 1 1
  • φ ( 6 ) = 2 \varphi(6)=2 φ(6)=2,即 1 1 1 5 5 5
  • φ ( 12 ) = 4 \varphi(12)=4 φ(12)=4,即 1 1 1 5 5 5 7 7 7 11 11 11

怎样求出一个数的欧拉函数呢?公式呈上:

对于任意正整数 n n n,若 n = P 1 k 1 × P 2 k 2 × ⋯ × P m k m n=P_1^{k_1} \times P_2^{k_2} \times \cdots \times P_m^{k_m} n=P1k1×P2k2××Pmkm。则有 φ ( n ) = n × ( 1 − 1 P 1 ) × ( 1 − 1 P 2 ) × ⋯ × ( 1 − 1 P m ) \varphi(n)=n\times (1-\frac{1}{P_1})\times (1-\frac{1}{P_2})\times \cdots \times (1-\frac{1}{P_m}) φ(n)=n×(1P11)×(1P21)××(1Pm1)

化简得: φ ( n ) = ∏ i = 1 m ( 1 − 1 p i ) \varphi(n)=\prod_{i=1}^m (1-\frac{1}{p_i}) φ(n)=i=1m(1pi1)

有这个公式,我们可以求出单个正整数的欧拉函数。即在分解素因数时计算欧拉函数。

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

代码

注意:在素因数分解完后如果 n n n 变成了素数,那 a n s ans ans 还要再运算一次。

inline int phi(int n) {
	int ans = n;
	for(register int i = 2;i <= sqrt(n);i ++)
		if(n % i == 0) {
			ans = ans / i * (i - 1);
			while (n % i == 0)
				n /= i;
		}
	if(n > 1)
		ans = ans / n * (n - 1);
	return ans;
}
欧拉函数公式的推导过程

接下来,我们一起推导在 O ( n ) O(\sqrt{n}) O(n ) 时间内求出欧拉函数的公式。

首先要知道几个性质:

  1. 对于任意素数 x x x,有 φ ( x ) = x − 1 \varphi(x)=x-1 φ(x)=x1。这个很好理解,即 x x x 与所有小于它的数互素。

  2. 对于任意素数 p p p,有 φ ( p k ) = p k − p k − 1 \varphi(p^k)= p^k-p^{k-1} φ(pk)=pkpk1。为什么呢?

    证明:因为 p p p 是素数,所以 p k p^k pk 的素因数只含有 p p p。那么在小于等于 p k p^k pk 的数中与其不互素的数便是 p p p 2 × p 2\times p 2×p 3 × p 3\times p 3×p ⋯ \cdots p k − 1 × p p^{k-1}\times p pk1×p,共 p k − 1 p^{k-1} pk1 个。得证。

  3. 欧拉函数是积性函数,但不是完全积性函数。这意味着 φ ( m × n ) = φ ( m ) × φ ( n ) \varphi(m\times n)=\varphi(m)\times \varphi(n) φ(m×n)=φ(m)×φ(n) 成立的前提是 gcd ⁡ ( m , n ) = 1 \gcd(m,n)=1 gcd(m,n)=1

了解完这几个性质后,我们开始推导:

N = p 1 k 1 × p 2 k 2 × p 3 k 3 × ⋯ × p n k n N=p_1^{k_1}\times p_2^{k_2}\times p_3^{k_3}\times \cdots \times p_n^{k_n} N=p1k1×p2k2×p3k3××pnkn

因为 p 1 , p 2 , p 3 , ⋯   , p n p_1,p_2,p_3,\cdots,p_n p1,p2,p3,,pn 都是素数,所以 p 1 k 1 , p 2 k 2 , ⋯ , p n k n p_1^{k_1},p_2^{k_2},\cdots,p_n^{k_n} p1k1p2k2pnkn 两两互素。

所以由性质 3 得:

φ ( N ) = φ ( p 1 k 1 ) × φ ( p 2 k 2 ) × ⋯ × φ ( p n k n ) \varphi(N)=\varphi(p_1^{k_1})\times \varphi(p_2^{k_2}) \times \cdots \times \varphi(p_n^{k_n}) φ(N)=φ(p1k1)×φ(p2k2)××φ(pnkn)

再由性质 2 得:

φ ( N ) = ( p 1 k 1 − p 1 k 1 − 1 ) × ( p 2 k 2 − p 2 k 2 − 1 ) × ⋯ × ( p n k n − p n k n − 1 ) \varphi(N)=(p_1^{k_1}-p_1^{k_1-1})\times(p_2^{k_2}-p_2^{k_2-1})\times\cdots\times(p_n^{k_n}-p_n^{k_n-1}) φ(N)=(p1k1p1k11)×(p2k2p2k21)××(pnknpnkn1)

提取公因数得:

φ ( N ) = p 1 k 1 × p 2 k 2 × ⋯ × p n k 2 × ( 1 − 1 p 1 ) × ( 1 − 1 p 2 ) × ⋯ × ( 1 − 1 p n ) \varphi(N)=p_1^{k_1}\times p_2^{k_2}\times \cdots \times p_n^{k_2} \times (1-\frac{1}{p_1})\times (1-\frac{1}{p_2})\times\cdots\times (1-\frac{1}{p_n}) φ(N)=p1k1×p2k2××pnk2×(1p11)×(1p21)××(1pn1)

最后把前 n n n 项合并一下便得到:

φ ( N ) = N × ( 1 − 1 p 1 ) × ( 1 − 1 p 2 ) × ⋯ × ( 1 − 1 p n ) \varphi(N)=N\times(1-\frac{1}{p_1})\times (1-\frac{1}{p_2})\times\cdots\times (1-\frac{1}{p_n}) φ(N)=N×(1p11)×(1p21)××(1pn1)

推导完毕。

欧拉函数的线性筛法

和素数一样,这样的算法求单个数的欧拉函数时间复杂度很优,但当题目需要求一串数的欧拉函数时便处理不了了。此时的时间复杂度便是 O ( n n ) O(n\sqrt{n}) O(nn )

那求一串数欧拉函数是否和求素数一样,有跟快甚至线性的方法呢?当然有,由刚刚的几个性质,我们可以在线性筛的基础上改进,在 O ( n ) O(n) O(n) 的时间内求得每个数的欧拉函数。

这里我们需要再引入一个性质:

  1. i   m o d   p = 0 i\bmod p=0 imodp=0,则有: φ ( p × i ) = φ ( i ) × p \varphi(p\times i)=\varphi(i)\times p φ(p×i)=φ(i)×p

    证明:

    b = gcd ⁡ ( n , i ) b=\gcd(n , i) b=gcd(n,i)

    因为 n n n i i i 不互素,所以 n = k 1 b n=k_1b n=k1b i = k 2 b i=k_2b i=k2b

    因为 n + i = ( k 1 + k 2 ) b n+i=(k_1+k_2)b n+i=(k1+k2)b,所以 n + i n+i n+i i i i 不互素。

    [ 1 , i ] [1,i] [1,i] 中与 i i i 不互素的整数 n n n i − φ ( i ) i-\varphi(i) iφ(i) 个。

    因为 n + i n+i n+i i i i 不互素,所以 [ 1 + i , i + i ] [1+i,i+i] [1+i,i+i],即 ( i , 2 i ] (i,2i] (i,2i] 中与 i i i 不互素的整数也是 i − φ ( i ) i-\varphi(i) iφ(i) 个,所以 [ 1 , i + p ] [1,i+p] [1,i+p] 中与 i i i 不互素的整数 p × i − p × φ ( i ) p\times i-p\times \varphi(i) p×ip×φ(i) 个。

    因为 i   m o d   p = 0 i\bmod p = 0 imodp=0 i i i p p p 没有不同的因数, [ 1 , i × p ] [1,i\times p] [1,i×p] 中与 i × p i\times p i×p 不互素的整数数量 p × i − p × φ ( i ) = i × p − φ ( i × p ) p\times i-p\times \varphi(i)=i\times p-\varphi(i\times p) p×ip×φ(i)=i×pφ(i×p)

    所以: φ ( i × p ) = p × φ ( i ) \varphi(i\times p)=p\times \varphi(i) φ(i×p)=p×φ(i)

我们一起边回顾线性筛代码,边了解求欧拉函数的方法:

定义phi[MAXN]存储欧拉函数。

首先,在开始筛之前我们先需要特判 1 1 1 的情况。同样,在求欧拉函数时,要先把 φ ( 1 ) \varphi(1) φ(1) 赋值为 1 1 1

 is_prime[1] = true;
 phi[1] = 1;

然后我们开始找素数。在找的过程中,如果遇到了素数 x x x,那我们就存储下 x x x。同时,由之前讲的性质 1 1 1 φ ( x ) = x − 1 \varphi(x)=x-1 φ(x)=x1。所以我们便可以对它的欧拉函数进行赋值。

for(register int i = 2;i <= n;i ++) {
	if(!is_prime[i]) {
		prime[++ cnt] = i;
		phi[i] = i - 1;
	}
	...
}

最后,在用找到的数 x x x 来筛素数的过程中。

若用来与 x x x 相乘的素数 y y y 不是 x x x 的最小的素因数,即比 x x x 的最小的素因数小,则说明 x x x 不包含 y y y 这个素因数,所以 gcd ⁡ ( x , y ) = 1 \gcd(x,y)=1 gcd(x,y)=1。此时,由性质 3 3 3 得到: φ ( x × y ) = φ ( x ) × φ ( y ) \varphi(x\times y)=\varphi(x)\times\varphi(y) φ(x×y)=φ(x)×φ(y)

若用来与 x x x 相乘的素数 y y y 已经与 x x x 不互素了,即此时 y y y x x x 的最小素因数。则根据性质 4 4 4 ,有: φ ( x × y ) = φ ( x ) × y \varphi(x\times y)=\varphi(x)\times y φ(x×y)=φ(x)×y

for(register int j = 1; j <= cnt , i * prime[j] <= n; j ++) {
	is_prime[i * prime[j]] = true;
	if(i % prime[j] == 0) {
		phi[i * prime[j]] = phi[i] * prime[j];
		break;
	}
	phi[i * prime[j]] = phi[i] * phi[prime[j]];
}
完整代码
int phi[MAXN] , prime[MAXN] , cnt;
bool is_prime[MAXN];

inline void Init_phi(int n) {
	is_prime[1] = true;
	phi[1] = 1;
	for(register int i = 2;i <= n;i ++) {
		if(!is_prime[i]) {
			prime[++ cnt] = i;
			phi[i] = i - 1;
		}
		for(register int j = 1;j <= cnt , i * prime[j] <= n;j ++) {
			is_prime[i * prime[j]] = true;
			if(i % prime[j] == 0) {
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			phi[i * prime[j]] = phi[i] * phi[prime[j]];
		}
	}
	return;
}

http://www.kler.cn/a/538925.html

相关文章:

  • Java 中 ArrayList 和 LinkedList 有什么区别?
  • 代码随想录算法训练营day38
  • (done) openMP学习 (Day13: 线程私有数据和如何支持库(Pi again),蒙特卡洛计算 Pi,线性同余法)
  • 单例模式几种实现
  • Faveo Helpdesk存在目录遍历漏洞(CVE-2024-37700)
  • 链表和 list
  • Linux下安装SVN服务端小白教程
  • 解锁Rust:融合多语言特性的编程利器
  • VLLM历次会议(2024.1)
  • 归一化与伪彩:LabVIEW图像处理的区别
  • ASAP Utilities:Excel 插件中的高效助手
  • (done) openMP学习 (Day10: Tasks 原语)
  • 【基于SprintBoot+Mybatis+Mysql】电脑商城项目之上传头像和新增收货地址
  • Elasticsearch入门技术:从零开始掌握全文搜索引擎
  • 深度理解如何使用DeepSeek-R1撰写论文:初学者指南
  • 校园网规划方案
  • 基于DeepSeek的具身智能高校实训解决方案——从DeepSeek+机器人到通用具身智能
  • DeepSeek JanusPro-7B本地安装-唯一正确版
  • 旋转位置编码(RoPE)公式详细推导过程
  • RocketMQ实战—8.营销系统业务和方案介绍
  • qt widget和qml界面集成到一起
  • 现代神经网络QA(LeNet/AlexNet/VGG/NiN/GooleNet/ResNet)-----一篇搞懂
  • Apache Commons Lang学习大纲
  • Windows逆向工程入门之高级语言与汇编语言
  • 【vscode+latex】实现overleaf本地高效编译
  • 51单片机俄罗斯方块清屏函数