欧拉函数
欧拉函数 $\varphi(n)$ 统计 $1$ 到 $n$ 中有多少个数与 $n$ 互质。
一句话算法
欧拉函数
问题模型
给定一个正整数
例如
核心直觉
一个数
如果:
那么要从
注意,公式只关心“有哪些不同质因子”,不关心每个质因子的次数。
算法步骤
- 令答案
ans = n。 - 从
p = 2开始试除到。 - 如果
p能整除当前n:- 说明
p是原数的一个质因子; - 更新
ans = ans / p * (p - 1); - 把当前
n中所有因子p除干净。
- 说明
- 循环结束后,如果
n > 1,说明剩下一个大质因子,再做一次:ans = ans / n * (n - 1)。
- 输出
ans。
算法证明
设
-
不互质的判定
与 不互质,等价于 至少含有一个 作为因子。 -
保留下来的比例
在
中, 的倍数占 。删掉这些倍数后,保留比例为: -
多个质因子的容斥
对所有不同质因子做容斥,保留下来的数量为:
-
代码等价
对每个质因子
,代码执行: 这正是把当前答案乘上
的整数写法。
所以算法正确计算了
复杂度分析
试除法最多枚举到
空间复杂度为
如果需要求
代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <bits/stdc++.h>
using namespace std;
long long euler_phi(long long n) {
long long ans = n;
for (long long p = 2; p * p <= n; p++) {
if (n % p != 0) continue;
ans = ans / p * (p - 1);
while (n % p == 0) n /= p;
}
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long n;
cin >> n;
cout << euler_phi(n) << '\n';
return 0;
}
测试用例
输入:
36
输出:
12
解释:
所以:
应用分类详解
欧拉函数的本质是统计模
一、互质计数
典型模式: 题目要求统计
识别信号: 出现“互质个数”“小于等于 n 且 gcd 为 1”。
核心建模: 把
| 应用场景 | 经典题目 | 核心思路 |
|---|---|---|
| 单点互质计数 | luogu-P2303 | 试除质因子求 |
| 互质对统计 | luogu-P2158 | 枚举分母时用欧拉函数计数 |
二、模意义下的可逆元素
典型模式: 判断模
识别信号: 出现“逆元”“剩余类”“与模数互质”。
核心建模: 模
| 应用场景 | 经典题目 | 核心思路 |
|---|---|---|
| 逆元存在性 | 模运算题 | gcd(a,n)=1 才存在逆元 |
| 剩余类群大小 | 数论证明题 | 可逆剩余类个数为 |
三、欧拉定理与指数降幂
典型模式: 大指数取模,并且底数与模数互质。
识别信号: 出现
核心建模: 若
可以用
| 应用场景 | 经典题目 | 核心思路 |
|---|---|---|
| 欧拉降幂 | 大指数取模题 | 先求 |
| 费马小定理 | 素数模数题 | 素数 |
经典例题
1. luogu-P2303
单个数欧拉函数模板题。分解 ans = ans / p * (p - 1)。
2. luogu-P2158
统计互质点对。核心是把每个分母对应的合法分子数量转化为欧拉函数值。
3. 欧拉降幂类题
当题目要求计算超大指数的
参考
- 欧拉函数公式
- 欧拉定理