【学习笔记】欧拉函数

0.概述

一个函数。只有毒瘤出题人会用到它。

1.定义

φ ( n ) = ∑ x = 1 n [ gcd ⁡ ( x , n ) = 1 ] \varphi(n)=\sum_{x=1}^{n}\big[\gcd(x,n)=1\big] φ(n)=x=1n[gcd(x,n)=1]

即,所有小于等于 n n n 的正整数,与 n n n 互质的有多少个。顺带一说,互质也可写为 a ⊥ b a\perp b ab

2.计算

2.1.积性函数

如果 a a a b b b 互质,那么
φ ( a b ) = φ ( a ) ⋅ φ ( b ) \varphi(ab)=\varphi(a)\cdot \varphi(b) φ(ab)=φ(a)φ(b)

证明:发现 gcd ⁡ ( x , a b ) = 1 \gcd(x,ab)=1 gcd(x,ab)=1 的充要条件是 gcd ⁡ ( x , a ) = 1 ∧ gcd ⁡ ( x , b ) = 1 \gcd(x,a)=1\wedge\gcd(x,b)=1 gcd(x,a)=1gcd(x,b)=1

那么设 x = k b + t    ( 0 ⩽ k < a ,    0 ⩽ t < b ) x=kb+t\;(0\leqslant k<a,\;0\leqslant t<b) x=kb+t(0k<a,0t<b),由 x ⊥ b ⇔ t ⊥ b x\perp b\Leftrightarrow t\perp b xbtb 可知,不同的 t t t 的数量是 φ ( b ) \varphi(b) φ(b) 个。

另一方面,对于某个 t t t,肯定有 { k b + t   m o d   a    ∣    k ∈ [ 0 , a ) } = { 0 , 1 , 2 , … , a − 1 } \{kb+t\bmod a\;|\;k\in[0,a)\}=\{0,1,2,\dots,a{\rm-}1\} {kb+tmodak[0,a)}={0,1,2,,a1},所以可行的 k k k 只有 φ ( a ) \varphi(a) φ(a) 个。二者相乘就是 φ ( a b ) = φ ( a ) ⋅ φ ( b ) \varphi(ab)=\varphi(a)\cdot\varphi(b) φ(ab)=φ(a)φ(b)

2.2.一般的计算

如果 p p p 是一个质数, k k k 是正整数,那么
φ ( p k ) = p k − 1 ( p − 1 ) \varphi(p^k)=p^{k-1}(p-1) φ(pk)=pk1(p1)

证明: x ⊥ p k ⇔ x ⊥ p ⇔ x = k p    ( 1 ⩽ k ⩽ p k − 1 ) x\perp p^k\Leftrightarrow x\perp p\Leftrightarrow x=kp\;(1\leqslant k\leqslant p^{k-1}) xpkxpx=kp(1kpk1),故 φ ( p k ) = p k − p k − 1 \varphi(p^k)=p^k-p^{k-1} φ(pk)=pkpk1,证毕。

再结合 积性函数,如果 n n n 的质因数分解是 n = p 1 t 1 p 2 t 2 p 3 t 3 … p m t m n=p_1^{t_1}p_2^{t_2}p_3^{t_3}\dots p_m^{t_m} n=p1t1p2t2p3t3pmtm ,那么
φ ( n ) = ∏ x = 1 m p x t x − 1 ( p x − 1 ) \varphi(n)=\prod_{x=1}^{m}p_x^{t_x-1}(p_x-1) φ(n)=x=1mpxtx1(px1)

2.3.特殊的计算

其实就是 一般的计算 变了形。
φ ( n ) = n ∏ p ∣ n ( 1 − 1 p ) \varphi(n)=n\prod_{p\mid n}\left(1-\frac{1}{p}\right) φ(n)=npn(1p1)

也可以理解为容斥,即考虑是否去掉某个质因数的倍数。注意这里隐式规定 p ∈ Prime p\in\text{Prime} pPrime

3.性质

3.0.积性函数

前面已经讲过 积性函数,这里就略过。

3.1.与 n n n 的关系

还有一个很美妙的结论(使得杜教筛在 φ \varphi φ 上可以大显身手):
∑ d ∣ n φ ( d ) = n \sum_{d|n}\varphi(d)=n dnφ(d)=n

快速证明:由容斥可知 i d ∗ μ = φ id*\mu=\varphi idμ=φ,两边同乘 I I I i d = φ ∗ I id=\varphi*I id=φI,证毕。其中 ∗ * 为狄利克雷卷积。

初等证明:将 { 1 , 2 , 3 , … , n } \{1,2,3,\dots,n\} {1,2,3,,n} 按如下规则划分: S d = { x ∣ gcd ⁡ ( x , n ) = d } S_d=\{x\mid\gcd(x,n)=d\} Sd={xgcd(x,n)=d} 。显然 S 1 ∪ S 2 ∪ ⋯ ∪ S n = { 1 , 2 , 3 , … , n } S_1\cup S_2\cup\cdots\cup S_n=\{1,2,3,\dots,n\} S1S2Sn={1,2,3,,n}

对于任意 x ∈ S d x\in S_d xSd,可以写成 x = k d    ( 1 ⩽ k ⩽ n d x=kd\;(1\leqslant k\leqslant\frac{n}{d} x=kd(1kdn 但不一定取遍 ) ) )

由定义, gcd ⁡ ( x , n ) = gcd ⁡ ( k d , n ) = d ⇒ gcd ⁡ ( k , n d ) = 1 \gcd(x,n)=\gcd(kd,n)=d\Rightarrow\gcd(k,\frac{n}{d})=1 gcd(x,n)=gcd(kd,n)=dgcd(k,dn)=1

这样一来, ∣ S d ∣ = φ ( n d ) |S_d|=\varphi(\frac{n}{d}) Sd=φ(dn) 。于是 n = ∑ d ∣ n ∣ S d ∣ = ∑ d ∣ n φ ( n d ) n=\sum_{d|n}|S_d|=\sum_{d|n}\varphi(\frac{n}{d}) n=dnSd=dnφ(dn),得证。

3.2.与莫比乌斯挂钩

∑ d ∣ n μ ( d ) d = φ ( n ) n \sum_{d|n}\frac{\mu(d)}{d}=\frac{\varphi(n)}{n} dndμ(d)=nφ(n)

比较显然且用处不大,此处从略。

3.3.“偶性”

2 ∣ φ ( n ) ( n ⩾ 3 ) 2\mid\varphi(n)\quad(n\geqslant 3) 2φ(n)(n3)

证明:如果 n n n 中含有任意一个奇素因数 p p p ,那么根据 一般的计算,可知 2 ∣ ( p − 1 ) ∣ φ ( n ) 2\mid(p-1)\mid\varphi(n) 2(p1)φ(n)

而不包含奇素因数的数只有 1 1 1 2 2 2

3.4.“收敛” 速度快

接下来的这一点,是很多题复杂度的保障:如果 2 ∣ n 2\mid n 2n ,那么 φ ( n ) ⩽ n 2 \varphi(n)\leqslant \frac{n}{2} φ(n)2n

证明: n n n 中含有 p = 2 p=2 p=2 这一质因子。根据 特殊的计算 φ ( n ) ⩽ n ( 1 − 1 p ) = n 2 \varphi(n)\leqslant n(1-\frac{1}{p})=\frac{n}{2} φ(n)n(1p1)=2n

再结合 偶性 可知,每次令 n i = φ ( n i − 1 ) n_i=\varphi(n_{i-1}) ni=φ(ni1),那么 i ⩾ ⌈ log ⁡ 2 n ⌉ i\geqslant\lceil\log_2n\rceil ilog2n 即可让 n i = 1 n_i=1 ni=1

3.5.欧拉降幂

我另开了一篇博客写这个……

4.代码实现

4.1.求单点值

直接用 一般的计算,暴搜质因数分解,复杂度 O ( n ) \mathcal O(\sqrt n) O(n )

int getPhi(int n){
	int res = 1;
	for(int x=2; x<=n/x; ++x){
		if(n%x) continue;
		n /= x, res *= (x-1);
		while(n%x == 0)
			n /= x, res *= x;
	}
	if(n != 1) res *= (n-1);
	return res;
}

我个人更喜欢写法二,感觉常数小一点。

long long __phi(long long n){
	long long res = n;
	for(int i=2; i<=n/i; ++i)
		if(n%i == 0){
			res -= res/i, n /= i;
			while(n%i == 0) n /= i;
		}
	if(n != 1) res -= res/n;
	return res;
}

4.2.奇怪法求单点值

int getPhi(int n){
	vector<int> ys; // 质因数 
	while(n != 1){
		d = findDivisor(n); // 找到一个质因数 
		ys.push_back(d);
		while(n%d == 0) n /= d;
	}
	sort(ys.begin(),ys.end());
	n = ys.size(); int res = n;
	for(int S=1; S<(1<<n); ++S){
		int sgn = 1, cnt = n;
// 是质因子集合S中每一个质因子的倍数的个数 
		for(int i=0; i<n; ++i)
			if(S>>i&1){
				sgn = -sgn;
				cnt /= ys[i];
			}
		res += sgn*cnt;
	}
	return res;
}

好处是什么呢?——可以求 ∑ x = 1 n [ gcd ⁡ ( x , m ) = 1 ] \sum_{x=1}^{n}[\gcd(x,m)=1] x=1n[gcd(x,m)=1] 。只需要稍稍作一点改动。

4.3.奇怪法

int getCoprime(int n,int m){
	vector<int> ys; // 质因数 
	while(m != 1){
		d = findDivisor(m); // 找到一个质因数 
		ys.push_back(d);
		while(m%d == 0) m /= d;
	}
	sort(ys.begin(),ys.end());
	m = ys.size(); int res = n;
	for(int S=1; S<(1<<m); ++S){
		int sgn = 1, cnt = n;
// 是质因子集合S中每一个质因子的倍数的个数 
		for(int i=0; i<n; ++i)
			if(S>>i&1)
				sgn = -sgn, cnt /= ys[i];
		res += sgn*cnt;
	}
	return res;
}

4.4.所有因数的单点值

能够做到 n \sqrt n n 的复杂度——也就是说,均摊 O ( 1 ) \mathcal O(1) O(1)

首先线性筛求出 x ∈ [ 1 , n ] x\in[1,\sqrt n] x[1,n ] φ ( x ) \varphi(x) φ(x),然后 O ( n ) \mathcal O(\sqrt n) O(n ) 的求出 φ ( n ) \varphi(n) φ(n) 。接下来要做的,就是研究 φ ( x ) ,    φ ( n x ) ,    φ ( n ) \varphi(x),\;\varphi(\frac{n}{x}),\;\varphi(n) φ(x),φ(xn),φ(n) 的关系。

观察 特殊的计算 中的右半部分,也就是 ∏ p ∣ n ( 1 − 1 p ) \prod_{p|n}(1-\frac{1}{p}) pn(1p1) ,将其记为 λ ( n ) \lambda(n) λ(n) 。于是就有 n λ ( n ) = φ ( n ) n\lambda(n)=\varphi(n) nλ(n)=φ(n)

考虑这样一个恒等式:记 d = gcd ⁡ ( x , n x ) d=\gcd(x,\frac{n}{x}) d=gcd(x,xn) ,那么
λ ( x ) ⋅ λ ( n x ) = λ ( n ) λ ( d ) \lambda(x)\cdot\lambda\left(\frac{n}{x}\right)=\lambda(n)\lambda(d) λ(x)λ(xn)=λ(n)λ(d)

证明:如果 p ∣ d p\mid d pd,在两边都会被计算两次;如果 p ∤ n p\nmid n pn,那么两边都一次也不会计算;其他的情况,两边都只计算一次。证毕。

把两边同时乘一个 n n n 可以得到:
x λ ( x ) ⋅ n x ⋅ λ ( n x ) = n λ ( n ) λ ( d ) ⇒ φ ( x ) φ ( n x ) = φ ( n ) φ ( d ) d ⇒ φ ( n x ) = φ ( n ) φ ( d ) d φ ( x ) x\lambda(x)\cdot \frac{n}{x}\cdot \lambda\Big(\frac{n}{x}\Big)=n\lambda(n)\lambda(d)\\ \Rightarrow \varphi(x)\varphi\Big(\frac{n}{x}\Big)=\varphi(n)\frac{\varphi(d)}{d}\\ \Rightarrow\varphi\Big(\frac{n}{x}\Big)=\frac{\varphi(n)\varphi(d)}{d\varphi(x)} xλ(x)xnλ(xn)=nλ(n)λ(d)φ(x)φ(xn)=φ(n)dφ(d)φ(xn)=dφ(x)φ(n)φ(d)

更形式化地,
φ ( a ) φ ( b ) = φ ( a b ) φ [ gcd ⁡ ( a , b ) ] gcd ⁡ ( a , b ) \varphi(a)\varphi(b)=\varphi(ab)\frac{\varphi[\gcd(a,b)]}{\gcd(a,b)} φ(a)φ(b)=φ(ab)gcd(a,b)φ[gcd(a,b)]

可以发现,这是自洽的——在 gcd ⁡ ( a , b ) = 1 \gcd(a,b)=1 gcd(a,b)=1 的情况下,自然满足 积性函数 咯。

gcd ⁡ ( x , n x ) \gcd(x,{n\over x}) gcd(x,xn) 怎样避免 O ( log ⁡ n ) \mathcal O(\log n) O(logn) 辗转相除呢?一种方法是,由于 x ⩽ n x\leqslant\sqrt{n} xn ,我们可以用快速 gcd ⁡ \gcd gcd 算法。这样不费脑子。

另一种方法是,求出 x ∈ [ 1 , n ] x\in[1,\sqrt{n}] x[1,n ] 的质因数表示。具体来说,存储最小质因数与对应的次数,以及除以它得到的值(即记录 x = p k v x=p^kv x=pkv 其中 p p p 为最小质因子且 p ⊥ v p\perp v pv )。我们已经用 O ( n ) \mathcal O(\sqrt{n}) O(n ) 搜出了 n n n 的质因数分解(用 unordered   map \texttt{unordered map} unordered map 桶计数就行,因为不同 p p p 的数量甚至低于 log ⁡ n \log n logn,可视为常数),那么 gcd ⁡ ( x , n x ) \gcd(x,{n\over x}) gcd(x,xn) p p p 的指数易得,最后乘上 gcd ⁡ ( v , n v )    ( v = x p k ) \gcd(v,{n\over v})\;(v={x\over p^k}) gcd(v,vn)(v=pkx) 即可。

5.例题

Naive Great Common Divisor \text{Naive Great Common Divisor} Naive Great Common Divisor

电磁看题。应该算比较常规的方法。

The Luckiest Number \text{The Luckiest Number} The Luckiest Number

点此跳转。用欧拉公式解决关于 x x x 的方程 a x ≡ 1 ( m o d b ) a^x\equiv 1\pmod b ax1(modb)

POAIBE \text{POAIBE} POAIBE

电磁跳转 p.s. \text{p.s.} p.s. 这个名字是缩写。

杜教筛求 φ \varphi φ 的前缀和

我们已经知道了 φ ∗ I = i d \varphi*I=id φI=id ,直接用即可。

放公式:令 S n = ∑ i = 1 n φ ( i ) S_n=\sum_{i=1}^{n}\varphi(i) Sn=i=1nφ(i) ,一定有
S n = n ( n + 1 ) 2 − ∑ d = 1 n S ( ⌊ n d ⌋ ) S_n=\frac{n(n+1)}{2}-\sum_{d=1}^{n}S(\lfloor\frac{n}{d}\rfloor) Sn=2n(n+1)d=1nS(dn)

map<int,long long> wk; /* WK(freopen) or2 */
long long djs(int n){
	if(n < SqrtN)
		return phi[n]; /* 线性筛中得到的结果 */
	if(wk.count(n)) return wk[n]; /* 记忆化 */
	long long res = 1ll*n*(n+1)>>1;
	for(int l=1,r; l<=n; l=r){
		r = n/(n/l)+1; /* 整除分块 */
		res -= (r-l)*djs(n/l);
	}
	return wk[n] = res;
}

复杂度是 O ( n 2 3 ) \mathcal O(n^{2\over 3}) O(n32) 的。计算过程我放在别的博客的不显眼之处了,不知道也罢

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值