欧拉函数
欧拉函数
欧拉函数是一类非常重要的数论函数
建议阅读 数论函数基础 章节,了解基本概念与先要知识
全文 绝大多数 内容是对 [0] 中讲述的 粗略抄写 和 胡乱加工
1. 定义与性质
定义
在 \([1, n]\) 中与 \(n\) 互质的数的个数,记作 \(\varphi (n)\)
形式化的说,\(\varphi (n) = \sum _ {i = 1} ^ n [i \perp n]\)
性质
-
显然,当 \(n \in \mathbb P\) 时,有 \(\varphi (n) = n - 1\)
质数和 小于它的所有数 互质
-
在 \([1, p ^ k]\) 中所有非 \(p\) 整倍数的数均与 \(p ^ k\) 互质,故有 \(\varphi (p ^ k) = (p - 1) p ^ {k - 1}\)
证明显然
-
\(\varphi\) 是 积性函数,即若 \(a \perp b\),则 \(\varphi (ab) = \varphi (a) \varphi (b)\)
数论函数基础 - 常见函数,分类及证明 中给出了 两种思路的详细证明
-
计算式 \(\varphi (n) = \prod \varphi (p ^ {c}) = \prod {p ^ c \times \dfrac {p - 1} p} = n \prod {\dfrac {p - 1} p}\)
根据前两条性质,以及 唯一分解 容易证明
-
若 \(a \mid b\),则 \(\varphi (ab) = a \times \varphi (b)\)
由于 \(a \mid b\),故 \(b\) 的 质因数 包含 \(a\) 的 质因数
换言之,\(b\) 的 本质不同质因数集 等于 \(ab\) 的 本质不同质因数集
故根据计算式 \(\varphi (ab) = ab \prod \dfrac {p - 1} p = a (b \prod \dfrac {p - 1} p) = a \times \varphi (b)\)
同理可以证明 \(a \mid b\) 时有 \(\varphi (a) \mid \varphi (b)\)(\(\prod\) 部分可以整除)
-
若 \(n > 2\),则 \(2 \mid \varphi (n)\)
考虑 计算式,\(p ^ c \times \dfrac {p - 1} p\) 当且仅当 \(p = 2, c = 1\) 时为 奇数,然后容易证明
-
使得 \(\gcd (n, x) = d, x \in [1, n]\) 的 \(x\) 个数为 \(\varphi \left ( \dfrac n d \right)\)
令 \(a = \dfrac n d, b = \dfrac x d\),于是有 \(a \perp b\),然后就 根据定义显然 了
-
\(\sum _ {d \mid n} \varphi (d) = n\),也被称为 欧拉反演
这里给出一种不同于 [0] 中的证明思路
我们考虑使用 莫比乌斯反演,即 \(f (n) = \sum _ {d \mid n} g (d) \Longleftrightarrow g (n) = \sum _{d \mid n} \mu (d) f \left ( \dfrac n d \right)\)
我们代入 \(f (n) = n, g (n) = \varphi (n)\),于是我们尝试证明 \(\varphi (n) = \sum _ {d \mid n} \mu (d) \times \dfrac n d\)
考虑 \(\mu\) 的特性,当且仅当 \(d = \prod p\)(\(p\) 互不相同 且是 \(n\) 的 质因子)时,才会有贡献
而当 \(d\) 有 偶数个质因子 时,\(\mu (d)\) 为 正,反之 \(\mu (d)\) 贡献为 负
这与计算式 \(\varphi (n) = n \prod \dfrac {p - 1} p = n \prod \left (1 - \dfrac 1 p \right)\) 的 容斥系数 相符合
容易知道它们相等
不够直观的话我们来举个例子,设有 \(n = p_1 ^ 2 \times p_2 ^ 3 \times p_3\)
根据 计算式
\[\begin {aligned} \varphi (n) &= n \prod \left ( 1 - \dfrac 1 p \right) \\ &= n \left ( 1 - \dfrac 1 {p_1} \right) \left ( 1 - \dfrac 1 {p_2} \right) \left ( 1 - \dfrac 1 {p_3} \right) \end {aligned} \]而使得 \(\mu (d) \neq 0\) 的 \(d\) 显然只有 \(1, p_1, p_2, p_3, p_1p_2, p_2p_3, p_1p_3, p_1p_2p_3\) 这几种取值
对应有式子
\[\begin {aligned} \varphi (n) = 1 - (\dfrac n {p_1} + \dfrac n {p_2} + \dfrac n {p_3}) + (\dfrac n {p_1p_2} + \dfrac n {p_2p_3} + \dfrac n {p_1p_3}) - \dfrac n {p_1p_2p_3} \end {aligned} \]显然上下相等
2. 线性筛欧拉函数
根据 计算式,我们有一个 简易 的实现,我们知道
其实就是每个 质因数 只计算一次贡献,可以写出代码如下
inline void Sieve () {
phi[1] = 1;
for (uint32_t i = 2; i <= N; ++ i) {
if (!Vis[i]) pri[++ Cnt] = i, phi[i] = i - 1;
for (uint32_t k = 1; k <= Cnt && pri[k] * i <= N; ++ k) {
Vis[i * pri[k]] = 1;
if (i % pri[k] == 0) {
phi[i * pri[k]] = phi[i] * pri[k];
break ;
}
else phi[i * pri[k]] = phi[i] * (pri[k] - 1);
}
}
}
我们注意到 \(\varphi (p ^ k) = p \times \varphi (p ^ {k - 1}) ~ (k > 1)\),而 \(\varphi (p) = p - 1\),故 \(\varphi (p ^ k) = \varphi (p ^ {k - 1}) p\)
3. 欧拉定理
其实就是 费马小定理 的 \(\operatorname {ex}\),可以拓展到部分 非素数的模数 情况
我们发现,\(\{kn \bmod m\ | k \perp m, k \in [0, m) \} = \{k, | k \perp m, k \in [0, m)\}\)
也就是说当 \(k, n \perp m\) 时,\(kn \bmod m\) 的余数就是 与 \(m\) 互质的数的某种排列
证明与前面 费马小定理 相似,显然两个集合元素个数均为 \(\varphi (m)\) 个,只需证明 元素不重
考虑反证,相同时必然不符合 互质条件,故易得
于是我们把这 \(\varphi (m)\) 数相乘,显然其在 \(\bmod m\) 意义下成立,即有
\[(\prod kn) \bmod m \equiv \prod (kn \bmod m) \pmod m \]故容易有 \(n ^ {\varphi (m)} \prod (kn \bmod m) \equiv \prod (kn \bmod m) \pmod m\)
可以知道 \(\prod (kn \bmod m) \perp m\),故两边可以同时 除掉这一部分,得到 \(n ^ {\varphi (m)} \equiv 1 \pmod m\)
4. 扩展欧拉定理
证明似乎需要 巨大量分讨?今天脑子太糊了,鸽了
转一个 \(OI - Wiki\) 上的证明 [1]
形式证明
证明转载自 synapse7,并进行了一些整理。
- 命题: \(a\) 的从 0 次, 1 次到 \(b\) 次幂模 \(m\) 构成的序列中,存在 \(r\) 和 \(s\) ,使得前 \(r\) 个数(即从 \(a^0 \bmod m\) 到 \(\left.a^{r-1} \bmod m\right)\) 互不相同,从第 \(r\) 个数开始,每 \(s\) 个数就循环一次。
证明:
- 由鸽巢定理易证。
我们把 \(r\) 称为 \(a\) 幂次模 \(m\) 的循环起始点, \(s\) 称为循环长度。(注意: \(r\) 可以为 0 )
用公式表述为: \(\forall i \geq r, a^i \equiv a^{i+s}(\bmod m)\)
2. 命题: \(a\) 为素数的情况,该式成立。证明:
- 若模 \(m\) 不能被 \(a\) 整除,而因为 \(a\) 是一个素数,那么 \(\operatorname{gcd}(a, m)=1\) 成立,根据欧拉定理,容易证明该式成立。
- 若模 \(m\) 能被 \(a\) 整除,那么存在 \(r\) 和 \(m^{\prime}\) 使得 \(m=a^r m^{\prime}\) ,且 \(\operatorname{gcd}\left(a, m^{\prime}\right)=1\) 成立。所以根据欧拉定理有 \(a^{\varphi\left(m^{\prime}\right)} \equiv 1\left(\bmod m^{\prime}\right)\) 。
又由于 \(\operatorname{gcd}\left(a^r, m^{\prime}\right)=1\) ,所以根据欧拉函数的求值规则,容易得到:
\(\varphi(m)=\varphi\left(m^{\prime}\right) \times(a-1) a^{r-1}\) ,即我们有: \(\varphi\left(m^{\prime}\right) \mid \varphi(m)\) 。
所以 \(a^{\varphi\left(m^{\prime}\right)} \equiv 1\left(\bmod m^{\prime}\right), \varphi\left(m^{\prime}\right) \mid \varphi(m) \Longrightarrow a^{\varphi(m)} \equiv 1\left(\bmod m^{\prime}\right)\), 即 \(a^{\varphi(m)}=k m^{\prime}+1\)
,两边同时乘以 \(a^r\) ,得 \(a^{r+\varphi(m)}=k m+a^r\) (因为 \(m=a^r m^{\prime}\) )
所以对于 \(m\) 中素因子 \(a\) 的次数 \(r\) 满足: \(a^r \equiv a^{r+\varphi(m)}(\bmod m)\) 。我们可以简单变换形式,得到 推论:\[b>r \Longrightarrow a^b \equiv a^{r+((b-r) \bmod \varphi(m))} \quad(\bmod m) \]又由于 \(m=a^r m^{\prime}\) ,所以 \(\varphi(m)=\varphi\left(a^r\right) \varphi\left(m^{\prime}\right) \geq \varphi\left(a^r\right)=a^{r-1}(a-1) \geq r\) (tips: \(a\) 是素数,最小是 2 ,而 \(r \geq 1\) )。
所以因为 \(\varphi(m) \geq r\) ,故有:\[a^r \equiv a^{r+\varphi(m)} \equiv a^{r \bmod \varphi(m)+\varphi(m)} \quad(\bmod m) \]所以
\[a^b \equiv a^{r+(b-r) \bmod \varphi(m)} 即 $a^b \equiv a^{b \bmod \varphi(m)+\varphi(m)}(\bmod m)$ 。 \]
- 命题: \(a\) 为素数的幂的情况,该式成立
证明:
- 不妨令 \(a=p^k\) ,是否依然有 \(\forall r, a^r \equiv a^{r+\varphi(m)}(\bmod m)\) ?
答案是肯定的,由命题1 可知存在 \(s\) 使得 \(a^s \equiv 1(\bmod m)\) ,所以 \(p^{\operatorname{lcm}(s, k)} \equiv 1(\bmod m)\) ,所以令 \(s^{\prime}=\frac{s}{\operatorname{gcd}(s, k)}\) 时,我们能有 \(p^{s^{\prime} k} \equiv 1(\bmod m)\) 。
此时有关系: \(s^{\prime} \mid s\) 且 \(s \mid \varphi(m)\) ,且 \(r^{\prime}=\left\lceil\frac{r}{k}\right\rceil \leq r \leq \varphi(m)\) ,由 \(r^{\prime}, s^{\prime}\) 与 \(\varphi(m)\) 的关系,依然可以得到 \(a^b \equiv a^{b \bmod \varphi(m)+\varphi(m)}(\bmod m)\) 。
4. 命题: \(a\) 为合数的情况,该式成立。证明:
- 只证 \(a\) 拆成两个素数的幂的情况,大于两个的用数学归纳法可证。设 \(a=a_1 a_2\), 其中 \(a_i=p_i^{k_i}\) ,而 \(a_i\) 的循环长度为 \(s_i\) ;
则 \(s \mid \operatorname{lcm}\left(s_1, s_2\right)\) ,由于 \(s_1\left|\varphi(m), s_2\right| \varphi(m)\) ,那么 \(\operatorname{lcm}\left(s_1, s_2\right) \mid \varphi(m)\) ,所以 \(s \mid \varphi(m)\) , \(r=\max \left(\left\lceil\frac{r_i}{k_i}\right\rceil\right) \leq \max \left(r_i\right) \leq \varphi(m)\) ;
由 \(r, s\) 与 \(\varphi(m)\) 的关系,依然可以得到 \(a^b \equiv a^{b \bmod \varphi(m)+\varphi(m)}(\bmod m)\) 。证毕。
Luogu P5091 【模板】扩展欧拉定理
啊对,就是板子
#include <bits/stdc++.h>
uint32_t A, M, P, K;
bool BiggerthanM;
std::string B;
inline uint32_t phi (uint32_t x) {
uint32_t Ret = x;
for (uint32_t i = 2; i <= sqrt (x); ++ i)
if (x % i == 0) {
Ret = Ret / i * (i - 1);
while (x % i == 0) x = x / i;
}
if (x > 1) Ret = Ret / x * (x - 1);
return Ret;
}
inline uint32_t phi_mod_b () {
uint32_t Ret = 0, Val = 0;
for (uint32_t i = 0; i < B.size (); ++ i) {
Ret = (Ret * 10 + (B[i] - '0')) % P, Val = Val * 10 + (B[i] - '0');
if (Val > M) BiggerthanM = 1;
}
return Ret;
}
inline uint32_t qpow (uint32_t a, uint32_t b) {
uint32_t Ret = 1;
while (b) {
if (b & 1) Ret = 1ull * a * Ret % M;
a = 1ull * a * a % M, b >>= 1;
}
return Ret;
}
int main () {
std::ios::sync_with_stdio(0);
std::cin.tie(0), std::cout.tie(0);
std::cin >> A >> M >> B;
P = phi (M), K = phi_mod_b ();
if (std::__gcd (A, M) == 1) std::cout << qpow (A, K) << '\n';
else if (!BiggerthanM) std::cout << qpow (A, atoi (B.data ())) << '\n';
else std::cout << qpow (A, K + P) << '\n';
return 0;
}
Luogu P2158 [SDOI2008] 仪仗队
唐氏题,转化一下题意就是求 分母小于 \(N\) 的 最简分数个数
容易想到 欧拉函数前缀和,然后随便做
尝试了一下用 \(Farey\) 序列来 暴力,优化的好可以过 \(35000\),非常牛
(甚至本地可以过 \(40000\))
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
const int MAXN = 40005;
uint32_t pri[40005], phi[40005];
uint32_t Cnt = 0, Sum = 0, N;
bool Vis[40005];
void Sieve () {
phi[1] = 1;
for (uint32_t i = 2; i <= N; ++ i) {
if (!Vis[i]) pri[++ Cnt] = i, phi[i] = i - 1;
for (uint32_t j = 1; j <= Cnt && pri[j] * i <= N; ++ j) {
Vis[i * pri[j]] = 1;
if (i % pri[j] == 0) {
phi[i * pri[j]] = pri[j] * phi[i];
break ;
}
phi[i * pri[j]] = phi[i] * (pri[j] - 1);
}
}
}
int main () {
scanf ("%u", &N);
Sieve ();
for (uint32_t i = 1; i < N; ++ i) Sum += phi[i];
printf ("%u\n" ,(Sum << 1) + (N > 1));
return 0;
}
#include <bits/stdc++.h>
struct Frac {
uint32_t x, y;
inline Frac operator + (const Frac &a) const {
return {x + a.x, y + a.y};
}
};
uint32_t N, Cnt;
inline void DFS (const Frac l, const Frac r) {
Frac m = (l + r);
if (m.x > N || m.x < m.y || m.y > N) [[unlikely]] return ;
++ Cnt, DFS (l, m), DFS (m, r);
}
int main () {
std::cin >> N, -- N;
// if (N > 35000) return 1;
DFS ({0, 1}, {1, 0});
std::cout << (Cnt << 1) + (N > 0) << '\n';
return 0;
}