欧拉函数 笔记
看着书上的定理,自己亲手证明。
定义
∀a,b∈N,若 gcd(a,b)=1,则称 a,b 互质。
定义 1 到 n 中与 n 互质的数的个数为欧拉函数,记作 φ(n)。
计算式
若在唯一分解定理中,n=p1c1p2c2⋯pmcm,则 φ(n)=n∏i=1m(1−pi1),证明如下:
从最简单的开始。设 p, q 都是 n 的因子,那么 n 以内 p, q 的倍数有 n / p, n / q 个,它们的公倍数有 n / pq 个。根据容斥原理,公倍数被算了两次,要减去一次。推广可得(i=j):
φ(n)=n−∑pin+∑pipjn−⋯+(−1)m∑p1p2⋯pnn=n[1−∑pi1+∑pipj1−⋯+(−1)m∑p1p2⋯pm1]=ni=1∏m(1−pi1)
性质
书上六条性质,我改成了四条。
性质1
∀n>1,1∼n 中与 n 互质的数的和为 2nφ(n)。
证明:
设1∼n 中与 n 互质的数的和为 S。
由更相减损术得:
gcd(n,x)=gcd(n,n−x)
所以不与 n 互质的数成对出现(包括 0),且它们的平均值为 n/2。
所以:
n−φ(n)+121n(n+1)−S2n2+n−S−SS=2n=2n2−nφ(n)+n=2−nφ(n)=2nφ(n)
性质2
若 gcd(a,b)=1,则 φ(ab)=φ(a)φ(b)。
证明:
设 a=∏i=1mpici,b=∏i=m+1m+npici,则 ab=∏i=1m+npici。
则 φ(a)=a∏i=1n(1−pi1),φ(b)=b∏i=m+1m+n(1−pi1),φ(ab)=ab∏i=1m+n(1−pi1)。
而 φ(a)φ(b)=a∏i=1n(1−pi1)×b∏i=m+1m+n(1−pi1)=ab∏i=1m+n(1−pi1)。
所以 φ(ab)=φ(a)φ(b)。
推广:
定义积性函数 f(x) 为满足当 gcd(a,b)=1 时,f(ab)=f(a)f(b) 的函数。
对于积性函数 f(x),显然有:
若在算术基本定理中 x=∏i=1mpici,则 f(x)=∏i=1mf(pici)
性质3
设 p 为质数且 p∣n,则有:
φ(n)={φ(n/p)⋅pφ(n/p)⋅(p−1)p2∣np2∤n
证明:
若 p2∣n,则 p∣(n/p)。这意味着 n 和 n/p 的质因数集合相同。那么:
φ(n/p)φ(n)=n/p∏(1−pi)n∏(1−pi)=n/pn=p
即 φ(n)=φ(n/p)⋅p。
若 p2∤n 则 gcd(n/p,p)=1,根据性质2,有:
φ(n)=φ(n/p)φ(p)=φ(n/p)⋅(p−1)
性质4
∑d∣nφ(d)=n。
证明:
设 f(x)=∑d∣xφ(d)。
若 gcd(n,m)=1,则 ∀d1∣n,d2∣m,有 gcd(d1,d2)=1 且 d1d2∣nm,那么 φ(d1)φ(d2)=φ(d1d2)。同时 nm 的约数集为 {d1d2}。
所以:
d1∣n∑φ(d1)×d2∣m∑φ(d2)=d∣nm∑φ(d)
即:
f(n)f(m)=f(nm)
这意味着 f(x) 是一个积性函数。
若 p 是质数,则:
f(pc)=φ(1)+φ(p)+φ(p2)+⋯+φ(pc)=1+(p−1)+p(p−1)+⋯+pc−1(p−1)=1−1+p−p+p2+⋯−pc−1+pc=pc
所以若 n=∏i=1mpici,则:
d∣n∑φ(d)=f(n)=i=1∏mf(pici)=i−1∏mpici=n
计算
(以下涉及一些简单的 C++ 代码和埃筛、线性筛的基础,如果不会,可以自己上网查找资料)
注:
- 埃筛:Eratosthenes 筛法的简称。
- 线性筛:又称欧拉筛。
计算单个数的欧拉函数
利用试除法和欧拉函数计算式可求 φ(n),时间复杂度为 O(n)。代码很简单,书上也有,不用另外写了。
计算 1 到 n 中所有数的欧拉函数
利用埃筛
根据计算式计算。
先来回顾埃筛板子:
void primes(int n) {
memset(v, 0, sizeof(v));
for (int i = 2; i <= n; ++i) {
if (v[i]) continue;
for (int j = i; j <= n / i; ++j)
v[i * j] = 1;
}
}
计算欧拉函数之前,可以先初始化 phi[i] = i
。
注意到第 6 行 i
是质数,i * j
是 i
的倍数,那么 phi[i*j] = phi[i*j] / i * (i - 1)
。
修改后的代码如下:
void euler(int n) {
for (int i = 2; i <= n; ++i)
phi[i] = i;
for (int i = 2; i <= n; ++i) {
if (phi[i] != i) continue; // 直接判断欧拉函数有没被改变过
phi[i] = i - 1;
for (int j = 2; j <= n / i; ++j) // 算欧拉函数的话一定要从 2 开始
phi[i*j] = phi[i*j] / i * (i - 1);
}
}
埃筛的时间复杂度为 O(nlogn),一般不够用。
利用线性筛
印象中,某大佬说过,线性筛天生就适合计算积性函数。e.g. φ(n),μ(n)。
原理:性质3
设 p 为质数且 p∣n,则有:
φ(n)={φ(n/p)⋅pφ(n/p)⋅(p−1)p2∣np2∤n
等价于:
φ(np)={φ(n)⋅pφ(n)⋅(p−1)p∣np∤n
在线性筛中,第一种情况意味着 p=v(n)。这里的 v(n) 指的是 n 的最小质因数。
线性筛求欧拉函数代码:
void euler(int n) {
for (int i = 2; i <= n; ++i) {
if (!v[i]) prime[++m] = v[i] = i, phi[i] = i - 1;
for (int j = 1; j <= m; ++j) {
if (prime[j] > v[i] || prime[j] > n / i) break;
int nxt = prime[j] * i;
v[nxt] = prime[j];
phi[nxt] = phi[i] * (v[i]==prime[j] ? prime[j] : prime[j]-1);
}
}
}
例题
这篇文章写不下了,另起一篇:
https://blog.nowcoder.net/n/edc43d04c64844c08f05485e10aa75fc