欧拉函数
欧拉函数
定义
一组数 \(x_1,x_2,\dots,x_s\) 称为是模 \(m\) 的既约剩余系(简称缩系),如果对 \(\forall j,s \in Z,i\le j \le s,(x_j,m)=1\) ,并定义 \(\phi(m)=s\) ,即 \(\{1,2,3,\cdots,m\}\) 中与 \(m\) 互素的个数,\(\phi(n)\)称为欧拉函数。
通俗地讲,欧拉函数 \(\phi(n)\) 表示1~n中与n互质的数的个数。
举个例子:
在1~6中,只有 \(1\) 和 \(5\) 两个数字与6互质,故 \(\phi(6)=2\) 。
在1~18中,有 \(1,2,5,7,11,13,17\) 一共6个数字与18互质,故 \(\phi(18)=6\) 。
性质
-
如果一个数 \(p\) 是质数,那么它的欧拉函数为 \(p-1\),也就是说1~p-1的所有数字均与 \(p\) 互质。
-
设 \(m=m_1m_2(m\in \mathbb{N}^*)\),则有:若 \(m_1\) 与 \(m_2\) 互质,则 \(\phi(m)=\phi(m_1)\phi(m_2)\);若 \(m_1\) 与 \(m_2\) 不互质,则 \(\phi(m)=m_1\phi(m_2)\),其中 \(m_1\le m_2\).
-
对于 \(\forall m\in \mathbb{N}^*\),有
\[\sum\limits_{d|m} \phi(d)=\sum\limits_{d|m}\phi\left(\frac{m}{d}\right) \] -
欧拉定理:
\[若\space a\space与\space m\space互质,则\space a^{\phi(m)}\equiv 1 (mod\space m). \]
公式
根据算术基本定理,一个数N可以被唯一分解为有限个质数之积的形式:
在此基础上, \(\phi(N)\)的计算公式为:
举个例子:
证明
根据容斥原理:
1.从 1~N 中去掉 \(P_1,P_2,...P_k\) 的所有倍数。(共减 \(C_k^1\) 项)
2.再加上所有 \(P_i*P_j\) 的倍数。(这些数字被重复去掉了,共加 \(C_k^2\) 项)
3.再减去所有 \(P_i*P_j*P_h\) 的倍数。(共减 \(C_k^3\) 项)
以此类推...
最终所得式子即为上述公式的展开式。
求一个数的欧拉函数
时间复杂度
直接用公式求解,决速步为分解质因数,因此时间复杂度为 \(O(\sqrt n)\).
代码
由于C++中 / 为整除运算,我们也不希望出现小数,因此将公式稍微变形,将 \(res\times \left(1-\frac{1}{P}\right)\) 的操作改为等价的 \(\frac{res}{P}\times (P-1)\) 操作。
int phi(int n) {
int res = n, p = 2;
while (n != 1) {
if (n % p == 0) {
res = res / p * (p - 1);
while (n % p == 0) n /= p;
}
p++;
}
return res;
}
求n以内的每个数的欧拉函数
思路:
利用素数线性筛(欧氏筛法),结合欧拉函数的一些性质,改写为一个线性的筛法。
时间复杂度:
\(O(n)\)
代码:
#include <iostream>
using namespace std;
const int N = 1e6 + 5;
int p[N], t; //质数及下标
int phi[N]; //欧拉函数
bool s[N]; //是否为合数
void get_euler(int n) { //计算n以内的欧拉函数
phi[1] = 1;
for (int i = 2; i <= n; i++) {
if (!s[i]) {
p[++t] = i;
phi[i] = i - 1;
}
for (int j = 1; p[j] <= n / i; j++) {
s[i * p[j]] = true;
if (i % p[j] == 0) {
phi[i * p[j]] = phi[i] * p[j];
break;
}
phi[i * p[j]] = phi[i] * (p[j] - 1);
}
}
}
代码解释:
第13行:若 \(i\) 为质数,则 \(\phi(i) = i-1\).
第18行:此时 \(p[j]\) 为 \(i\) 的最小质因数,若:
则:
因此:
第21行:此时 \(p[j]\) 小于 \(i\) 的最小质因数,若:
则:
因此:

浙公网安备 33010602011771号