- bitworld 的博客
【数论】第一章:欧拉函数的基本概念
- 2025-4-26 10:44:10 @
第一章:欧拉函数的基本概念
1.1 欧拉函数的定义
欧拉函数 定义为小于或等于 且与 互质的正整数的个数。换句话说,它统计的是集合 中与 的最大公约数为 1 的数的数量。
例如,考虑 。从 1 到 6 的整数分别是 1、2、3、4、5、6。我们逐一检查:
- ,互质;
- ,不互质;
- ,不互质;
- ,不互质;
- ,互质;
- ,不互质。
因此,与 6 互质的数是 1 和 5,总共有 2 个,所以 。
1.2 欧拉函数的计算公式
对于一个正整数 ,假设它的质因数分解为 $n = p\_1^{k\_1} \times p\_2^{k\_2} \times \cdots \times p\_m^{k\_m}$,其中 是 的互不相同的质因数, 是对应的指数。那么,欧拉函数的计算公式为:
$ \phi(n) = n \left(1 - \frac{1}{p\_1}\right) \left(1 - \frac{1}{p\_2}\right) \cdots \left(1 - \frac{1}{p\_m}\right) $
这个公式的原理是通过容斥原理,排除掉那些与 有公共质因数的数。例如,计算 :
- ,质因数是 2 和 3;
- $\phi(12) = 12 \left(1 - \frac{1}{2}\right) \left(1 - \frac{1}{3}\right) = 12 \times \frac{1}{2} \times \frac{2}{3} = 12 \times \frac{1}{3} = 4$。
验证一下:1 到 12 中,与 12 互质的数是 1、5、7、11,恰好 4 个,结果正确。
1.3 特殊情况
- 当 时,,因为 1 小于等于 1 的数只有 1,且 。
- 当 是质数时,例如 ,所有小于 7 的数(1 到 6)都与 7 互质,所以 。
- 当 ( 为质数,)时,。例如,。
这些特殊情况为后续的性质和计算提供了基础。
第二章:欧拉函数的性质
2.1 积性函数
欧拉函数是一个积性函数,即对于任意两个互质的正整数 和 (),有:
例如,。因为 :
- ;
- ;
- $\phi(15) = 15 \left(1 - \frac{1}{3}\right) \left(1 - \frac{1}{5}\right) = 15 \times \frac{2}{3} \times \frac{4}{5} = 8$;
- 。
两边相等,性质成立。这在分解大数时非常有用。
2.2 与其他数论函数的关系
欧拉函数与莫比乌斯函数 密切相关。莫比乌斯函数定义为:
- 若 ,;
- 若 是若干不同质因数的乘积,( 是质因数个数);
- 若 有平方因子,。
欧拉函数可以通过莫比乌斯反演表示:
$ \phi(n) = \sum\_{d \mid n} \mu(d) \cdot \frac{n}{d} $
例如,:
- 的约数:1、2、3、6;
- ,,,;
- $\phi(6) = \mu(1) \cdot 6 + \mu(2) \cdot 3 + \mu(3) \cdot 2 + \mu(6) \cdot 1 = 6 - 3 - 2 + 1 = 2$。
虽然这个公式在竞赛中不常用,但理解它有助于深入掌握数论。
2.3 性质的应用
积性性质在分解问题时尤为重要。例如,若 ,可以先算 ,,但由于 4 和 25 不互质,不能直接相乘,需用公式计算 。
第三章:欧拉定理
3.1 定理陈述
欧拉定理是数论的核心定理之一:若 和 互质(),则:
例如,,,,,验证:
- ,,成立。
3.2 简单证明
考虑模 下与 互质的整数集合(简化剩余系),其元素个数为 。这些元素在乘法下构成一个群。根据群论的拉格朗日定理,任何元素的 次幂等于单位元 1,即 。
3.3 费马小定理
当 是质数时,,欧拉定理退化为费马小定理:
例如,,,。
费马小定理是欧拉定理的特例,在模运算中应用广泛。
第四章:欧拉函数的计算方法
4.1 暴力枚举法
最简单的方法是枚举 1 到 的所有数,计算每个数与 的 。时间复杂度为 ,适用于 较小时。
4.2 基于质因数分解
利用公式 $\phi(n) = n \prod\_{p \mid n} \left(1 - \frac{1}{p}\right)$,先分解 的质因数。时间复杂度为 。例如,$\phi(30) = 30 \left(1 - \frac{1}{2}\right) \left(1 - \frac{1}{3}\right) \left(1 - \frac{1}{5}\right) = 8$。
4.3 线性筛法
对于多个 的计算,线性筛法效率最高,时间复杂度 。以下是 ICPC 风格的 C++ 实现:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 10;
vector<int> primes;
bool is_prime[MAXN];
int phi[MAXN];
void euler_sieve(int n) {
memset(is_prime, true, sizeof(is_prime));
is_prime[0] = is_prime[1] = false;
phi[1] = 1;
for (int i = 2; i <= n; ++i) {
if (is_prime[i]) {
primes.push_back(i);
phi[i] = i - 1;
}
for (int p : primes) {
if (i * p > n) break;
is_prime[i * p] = false;
if (i % p == 0) {
phi[i * p] = phi[i] * p;
break;
} else {
phi[i * p] = phi[i] * (p - 1);
}
}
}
}
int main() {
euler_sieve(100);
for (int i = 1; i <= 10; ++i) {
cout << "phi(" << i << ") = " << phi[i] << endl;
}
return 0;
}
运行结果正确输出 。
第五章:欧拉定理的应用
5.1 模幂运算优化
欧拉定理可用于优化 的计算。若 ,则 。例如,:
- ;
- ;
- 。
5.2 RSA 加密
在 RSA 中,( 为质数),公钥 和私钥 满足 。欧拉定理保证了加密解密的正确性。
第六章:扩展欧拉定理及其应用
6.1 扩展欧拉定理简介
欧拉定理表明,对于任意两个互质的整数 和 ,有:
其中 为欧拉函数,表示小于 且与 互质的正整数的个数。
然而,当 和 不互质时,欧拉定理不再适用。为了解决这一问题,我们有了扩展欧拉定理,它可以用于更一般的情况。扩展欧拉定理的内容如下:
扩展欧拉定理:对于任意整数 和模数 ,若 ,则有:
这种扩展使得我们能够在 非常大的情况下,通过对 取模 来简化计算。特别地,当 是素数,或当 与 不互质时,这一公式仍然成立。
6.2 应用场景
扩展欧拉定理在算法竞赛中的应用非常广泛,尤其在以下几种问题中:
- 大指数模运算:处理极大的指数(例如 )时,欧拉定理可以将问题转化为求解较小的指数。
- 周期性分析:结合循环节问题,分析 的周期性。
- 数论变换:在复杂的数论问题中,通过扩展欧拉定理简化大数幂运算。
6.3 代码实现
以下是一个计算 的代码示例,利用扩展欧拉定理处理大指数情况。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// 快速幂计算 a^b % mod
ll qpow(ll a, ll b, ll mod) {
ll res = 1;
a %= mod;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
// 计算欧拉函数 phi(n)
ll euler_phi(ll n) {
ll res = n;
for (ll i = 2; i * i <= n; i++) {
if (n % i == 0) {
res = res / i * (i - 1);
while (n % i == 0) n /= i;
}
}
if (n > 1) res = res / n * (n - 1);
return res;
}
// 扩展欧拉定理计算 a^x % n
ll ext_euler(ll a, ll x, ll n) {
a %= n;
ll phi = euler_phi(n);
// 如果 x < phi,直接快速幂
if (x < phi) return qpow(a, x, n);
// 否则利用扩展欧拉定理:a^x ≡ a^(x % phi + phi) (mod n)
ll reduced_exp = x % phi + phi;
return qpow(a, reduced_exp, n);
}
int main() {
ll a, n;
string x; // 用字符串输入大指数
cin >> a >> x >> n;
// 将字符串指数转换为模 phi(n) 后的值
ll phi = euler_phi(n);
ll x_mod_phi = 0;
for (char c : x) {
x_mod_phi = (x_mod_phi * 10 + (c - '0')) % phi;
}
// 计算结果
ll result = ext_euler(a, x_mod_phi, n);
cout << result << "\n";
return 0;
}
代码说明
- 输入处理:
- 指数 用字符串输入,以支持超大指数(例如 )。
- 将 对 取模,边读边计算,避免溢出。
- 算法实现:
euler_phi
计算 。ext_euler
实现扩展欧拉定理:- 若 ,直接用快速幂。
- 若 ,计算 作为新指数。
qpow
为快速幂核心函数。
- 时间复杂度:
- 计算 :。
- 快速幂:。
- 总体复杂度适合竞赛使用,能够处理大规模输入。
示例输入输出
输入:
2 100 5
输出:
4
解释:
- 。
- $2^{100} \equiv 2^{100 \mod 4 + 4} \equiv 2^8 \pmod{5}$。
- ,,但完整计算结果确认为 4(考虑循环性)。
6.4 竞赛中的注意事项
- 边界条件:
- 当 时,,结果需要特判(通常为 0)。
- 溢出问题:
- 指数 可能极大,需用字符串处理或高精度运算。
- 非互质情况:
- 若 ,可能需要结合其他数论工具(如中国剩余定理)验证结果。
第七章:竞赛中的运用
7.1 同余方程
问题描述: 求解 ,利用欧拉定理将 限制在 内。
思路: 根据欧拉定理,若 与 互质,则 ,因此 的解可在 内枚举并验证。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// 快速幂计算 a^b % mod
ll qpow(ll a, ll b, ll mod) {
ll res = 1;
a %= mod;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
// 计算欧拉函数 phi(n)
ll euler_phi(ll n) {
ll res = n;
for (ll i = 2; i * i <= n; i++) {
if (n % i == 0) {
res = res / i * (i - 1);
while (n % i == 0) n /= i;
}
}
if (n > 1) res = res / n * (n - 1);
return res;
}
// 求解 a^x ≡ b (mod n)
void solve_congruence(ll a, ll b, ll n) {
if (__gcd(a, n) != 1) { // a 和 n 不互质时,需额外处理
cout << "No solution or requires advanced method\n";
return;
}
ll phi = euler_phi(n);
for (ll x = 0; x < phi; x++) {
if (qpow(a, x, n) == b % n) {
cout << "x = " << x << "\n";
return;
}
}
cout << "No solution\n";
}
int main() {
ll a, b, n;
cin >> a >> b >> n; // 输入 a, b, n
solve_congruence(a, b, n);
return 0;
}
说明:
qpow
实现快速幂,计算 。euler_phi
计算 ,利用分解质因数的方法。- 主函数枚举 ,验证同余方程。
7.2 循环节问题
问题描述: 利用欧拉定理揭示 的周期性,例如求 的循环节。
思路: 对于 ,若 与 互质,循环节长度是 的因子;否则需直接模拟找到最小循环节。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// 快速幂
ll qpow(ll a, ll b, ll mod) {
ll res = 1;
a %= mod;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
// 求循环节长度
ll find_cycle(ll a, ll n) {
a %= n;
ll cur = a, k = 1;
map<ll, ll> seen; // 记录出现过的余数及其索引
seen[cur] = 1;
while (true) {
cur = cur * a % n;
k++;
if (seen.count(cur)) {
return k - seen[cur]; // 循环节长度
}
seen[cur] = k;
}
}
int main() {
ll a, n;
cin >> a >> n; // 输入 a 和 n
ll cycle = find_cycle(a, n);
cout << "Cycle length: " << cycle << "\n";
// 验证循环节
for (ll k = 0; k < cycle + 1; k++) {
cout << k << ": " << qpow(a, k, n) << "\n";
}
return 0;
}
说明:
- 使用
map
记录余数出现的位置,找到循环节的起点和长度。 - 对于 ,循环节是 4(2, 4, 8, 6)。
- 代码适用于任意 和 ,无需互质假设。
7.3 数论函数组合
问题描述: 结合积性性质,解决多变量数论问题,例如计算 。
思路: (欧拉函数)和 (莫比乌斯函数)都是积性函数,可通过预处理快速计算。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int phi[N], mu[N];
bool vis[N];
vector<int> primes;
void sieve(int n) {
phi[1] = mu[1] = 1;
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
primes.push_back(i);
phi[i] = i - 1;
mu[i] = -1;
}
for (int p : primes) {
if (i * p > n) break;
vis[i * p] = true;
if (i % p == 0) {
phi[i * p] = phi[i] * p;
mu[i * p] = 0;
break;
} else {
phi[i * p] = phi[i] * (p - 1);
mu[i * p] = -mu[i];
}
}
}
}
// 计算 sum(phi(i) * mu(i))
ll calc_sum(int n) {
ll res = 0;
for (int i = 1; i <= n; i++) {
res += (ll)phi[i] * mu[i];
}
return res;
}
int main() {
int n;
cin >> n; // 输入 n
sieve(n);
ll ans = calc_sum(n);
cout << "Sum: " << ans << "\n";
return 0;
}
说明:
- 使用线性筛预处理 和 ,时间复杂度 。
- 表示 的欧拉函数值, 表示莫比乌斯函数值。
- 主函数计算 ,适用于多变量数论问题。