欧拉函数学习笔记
首先对于欧拉函数\(\varphi(n)\)的定义:小于等于\(n\)的数中,与\(n\)互质的数的个数。
\(\\\)
即:\(\varphi(n)=\sum\limits_{i=1}^{n}[\ \gcd(i,n)=1\ ]\)
\(\\\)
先看几个它的性质
\(\\\)
性质1:
\(\varphi(p)=p-1\)
\(\\\)
性质2:
\(\varphi(p^k) = p^{k} - 1 - (p^{k-1}) = p^{k} - p^{k - 1}\)
我们考虑\(\ p^{k},\ k\in\mathbb{Z},k\ >\ 1\),那么 \(p, 2p, 3p, ... , (p^{k-1}-1)\times p\) 不与\(p\) 互质,又\(p^{k}\)中 \(p\)为质数,所以没有其它互质的数,所以\(\varphi(p^k) = p^{k} - 1 - (p^{k-1}) = p^{k} - p^{k - 1}\)
\(\\\)
性质3:
\(\varphi(p^{k+1}) = p \times \varphi(p^{k})\)
由性质2得: \(\varphi(p^{k + 1}) = p^{k + 1} - p^{k} \qquad \varphi(p^k) = p^{k} - p^{k-1}\),所以有:\(\varphi(p^{k+1}) = p \times \varphi(p^{k})\)
\(\\\)
性质4:
\(\varphi(p_1^{k_1}p_2^{k_2}) = \varphi(p_1^{k1}) \times \varphi(p_2^{k2})\)
由性质2的思路,考虑与\(p_1^{k_1}\)最大公因数为\(p_1\),即为:\(p_1, 2p_1, 3p_1,..., (p_1^{k_1-1} - 1) \times p_1\) 共 \(p_1^{k_1-1}-1\)个
同理,有\(p_2^{k_2 - 1}-1\)个数与 \(p_2^{k_2}\) 最大公因数为\(p_2\)
但是会有重复统计的数,为 \(p_1p_2,2p_1p_2,3p_1p_2,...,(p_1^{k1-1}p_2^{k2-1}-1)p_1p_2\)共\((p_1^{k_1-1}p_2^{k_2-1}-1)\)个
所以
\(\varphi(p_1^{k_1}p_2^{k_2}) \\ = (p_1^{k_1}p_2^{k_2} - 1) - (p_1^{k_1-1}-1) - (p_2^{k_2 - 1}-1) + (p_1^{k_1-1}p_2^{k_2-1}-1) \\ = (p_1^{k_1} - p_1^{k_1-1})(p_2^{k_2}-p_2^{k_2-1}) \\ = \varphi(p_1^{k_1}) \varphi(p_2^{k_2})\)
\(\\\)
性质5:
\(\varphi(ab) = \varphi(a) \times \varphi(b), \ \gcd(a,b)=1\)
\(\\\)
性质6:
当\(n=\prod\limits_{i=1}^{m}p_i^{k_i}\)时,\(\varphi(n)=n\times \prod\limits_{i=1}^m \left( \dfrac{p_i - 1}{p_i}\right)\)
这个式子常用来求解单个\(\varphi(n)\)
\(\\\)
下面利用这些性质,考虑线性求欧拉函数。
根据性质5,有\(\varphi(i \times pri_j) = \varphi(i) \times \varphi(pri_j), \ \gcd(i,pri_j)=1\)
\(\\\)
当\(i\)与\(phi_j\)不互质时,令\(i \ = \ k \times pri_j^{t}, \ \gcd(k,pri_j)=1\),
此时,有
\(\varphi(i \times pri_j) \\ = \varphi(k\times pri_j \times pri_j^{t}) \\ = \varphi(k \times pri_j^{t+1}) \\ = \varphi(k) \times \varphi(pri_j^{t+1}) \\ = \varphi(k) \times pri_j \times \varphi(pri_j^{t}) \\ = pri_j \times \varphi(i)\)
所以,
\(\varphi(i \times pri_j) = \begin{cases}(pri_j-1) \times \varphi(i)&pri_j \nmid i \\ pri_j \times \varphi(i)&pri_j \mid i \end{cases}\)
那么对于\(i,i\geqslant2\),我们用\(vis\)数组来存储它的最小质因子,顺便也可以当作\(i\)之前是否被筛掉的判断依据。
如果筛到\(i\)时\(vis[i]==0\)表明\(i\)为一个质数,则\(\varphi(i)=i-1,\ vis[i]=i\),无论\(i\)是否为质数,都继续枚举目前所筛出的质数,当\(pri_{cur} \times i \geqslant n\)时或者\(pri_{cur} \geqslant vis[i] \ (如果pre_{cur}大于i的最小质因数,则pri_{cur} \times i会在 i 等于\dfrac{i \times pri_{cur}}{vis[i]}时被筛掉)\)时停止。
\(\\\)
#include <bits/stdc++.h>
using namespace std;
const int N = 4e4 + 5;
int n, cnt, vis[N], pri[N], phi[N];
int read() {
int x = 0, f = 1;
char c = getchar();
while (!isdigit(c)) {
if (c == '-') f = -1;
c = getchar();
}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline void varphi() {
phi[1] = 1;
for (int i = 2; i <= n - 1; ++ i) {
if (!vis[i]) {
pri[++cnt] = i;//记录目前所筛出的所有质数
phi[i] = i - 1;
vis[i] = i;
}
for (int j = 1; j <= cnt && pri[j] * i <= n - 1 && pri[j] <= vis[i]; ++j) {
vis[i * pri[j]] = pri[j];//存储的最小质因数
if (pri[j] == vis[i]) phi[i * pri[j]] = phi[i] * (pri[j] - 1);//即为线性筛中 此时 i % pri[j]==0
else phi[i * pri[j]] = phi[i] * (pri[j]);
}
}
}
int main() {
n = read();
varphi();
return 0;
}