欧拉函数

欧拉函数

欧拉函数是一类非常重要的数论函数

建议阅读 数论函数基础 章节,了解基本概念与先要知识


此处获取本节调试数据 / 代码包

全文 绝大多数 内容是对 [0] 中讲述的 粗略抄写胡乱加工


1. 定义与性质

定义

[1,n] 中与 n 互质的数的个数,记作 φ(n)

形式化的说,φ(n)=i=1n[in]


性质

  1. 显然,当 nP 时,有 φ(n)=n1

    质数和 小于它的所有数 互质

  2. [1,pk] 中所有非 p 整倍数的数均与 pk 互质,故有 φ(pk)=(p1)pk1

    证明显然

  3. φ积性函数,即若 ab,则 φ(ab)=φ(a)φ(b)

    数论函数基础 - 常见函数,分类及证明 中给出了 两种思路的详细证明

  4. 计算式 φ(n)=φ(pc)=pc×p1p=np1p

    根据前两条性质,以及 唯一分解 容易证明

  5. ab,则 φ(ab)=a×φ(b)

    由于 ab,故 b质因数 包含 a质因数

    换言之,b本质不同质因数集 等于 ab本质不同质因数集

    故根据计算式 φ(ab)=abp1p=a(bp1p)=a×φ(b)

    同理可以证明 ab 时有 φ(a)φ(b) 部分可以整除)

  6. n>2,则 2φ(n)

    考虑 计算式pc×p1p 当且仅当 p=2,c=1 时为 奇数,然后容易证明

  7. 使得 gcd(n,x)=d,x[1,n]x 个数为 φ(nd)

    a=nd,b=xd,于是有 ab,然后就 根据定义显然

  8. dnφ(d)=n,也被称为 欧拉反演

    这里给出一种不同于 [0] 中的证明思路

    我们考虑使用 莫比乌斯反演,即 f(n)=dng(d)g(n)=dnμ(d)f(nd)

    我们代入 f(n)=n,g(n)=φ(n),于是我们尝试证明 φ(n)=dnμ(d)×nd

    考虑 μ 的特性,当且仅当 d=pp 互不相同 且是 n质因子)时,才会有贡献

    而当 d偶数个质因子 时,μ(d),反之 μ(d) 贡献为

    这与计算式 φ(n)=np1p=n(11p)容斥系数 相符合

    容易知道它们相等

    不够直观的话我们来举个例子,设有 n=p12×p23×p3

    根据 计算式

    φ(n)=n(11p)=n(11p1)(11p2)(11p3)

    而使得 μ(d)0d 显然只有 1,p1,p2,p3,p1p2,p2p3,p1p3,p1p2p3 这几种取值

    对应有式子

    φ(n)=1(np1+np2+np3)+(np1p2+np2p3+np1p3)np1p2p3

    显然上下相等


2. 线性筛欧拉函数

根据 计算式,我们有一个 简易 的实现,我们知道

φ(n)={p×φ(np)p2n(p1)×φ(np)p2n

其实就是每个 质因数 只计算一次贡献,可以写出代码如下

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);
		}
	}
}

我们注意到 φ(pk)=p×φ(pk1) (k>1),而 φ(p)=p1,故 φ(pk)=φ(pk1)p


3. 欧拉定理

其实就是 费马小定理ex,可以拓展到部分 非素数的模数 情况

nφ(m)1(modm)nm

我们发现,{knmodm |km,k[0,m)}={k,|km,k[0,m)}

也就是说当 k,nm 时,knmodm 的余数就是 m 互质的数的某种排列

证明与前面 费马小定理 相似,显然两个集合元素个数均为 φ(m) 个,只需证明 元素不重

考虑反证,相同时必然不符合 互质条件,故易得

于是我们把这 φ(m) 数相乘,显然其在 modm 意义下成立,即有

(kn)modm(knmodm)(modm)

故容易有 nφ(m)(knmodm)(knmodm)(modm)

可以知道 (knmodm)m,故两边可以同时 除掉这一部分,得到 nφ(m)1(modm)


4. 扩展欧拉定理

ab{abmodφ(m)gcd(a,m)=1abgcd(a,m)1,b<φ(m)(modm)a(bmodφ(m))+φ(m)gcd(a,m)1,bφ(m)

证明似乎需要 巨大量分讨?今天脑子太糊了,鸽了

转一个 OIWiki 上的证明 [1]

形式证明
证明转载自 synapse7,并进行了一些整理。

  1. 命题: a 的从 0 次, 1 次到 b 次幂模 m 构成的序列中,存在 rs ,使得前 r 个数(即从 a0modmar1modm) 互不相同,从第 r 个数开始,每 s 个数就循环一次。

证明:

  • 由鸽巢定理易证。

我们把 r 称为 a 幂次模 m 的循环起始点, s 称为循环长度。(注意: r 可以为 0 )
用公式表述为: ir,aiai+s(modm)
2. 命题: a 为素数的情况,该式成立。

证明:

  • 若模 m 不能被 a 整除,而因为 a 是一个素数,那么 gcd(a,m)=1 成立,根据欧拉定理,容易证明该式成立。
  • 若模 m 能被 a 整除,那么存在 rm 使得 m=arm ,且 gcd(a,m)=1 成立。所以根据欧拉定理有 aφ(m)1(modm)
    又由于 gcd(ar,m)=1 ,所以根据欧拉函数的求值规则,容易得到:
    φ(m)=φ(m)×(a1)ar1 ,即我们有: φ(m)φ(m)
    所以 aφ(m)1(modm),φ(m)φ(m)aφ(m)1(modm), 即 aφ(m)=km+1
    ,两边同时乘以 ar ,得 ar+φ(m)=km+ar (因为 m=arm )
    所以对于 m 中素因子 a 的次数 r 满足: arar+φ(m)(modm) 。我们可以简单变换形式,得到 推论:

b>rabar+((br)modφ(m))(modm)

又由于 m=arm ,所以 φ(m)=φ(ar)φ(m)φ(ar)=ar1(a1)r (tips: a 是素数,最小是 2 ,而 r1 )。
所以因为 φ(m)r ,故有:

arar+φ(m)armodφ(m)+φ(m)(modm)

所以

abar+(br)modφ(m)$ababmodφ(m)+φ(m)(modm)$

  1. 命题: a 为素数的幂的情况,该式成立

证明:

  • 不妨令 a=pk ,是否依然有 r,arar+φ(m)(modm) ?

答案是肯定的,由命题1 可知存在 s 使得 as1(modm) ,所以 plcm(s,k)1(modm) ,所以令 s=sgcd(s,k) 时,我们能有 psk1(modm)
此时有关系: sssφ(m) ,且 r=rkrφ(m) ,由 r,sφ(m) 的关系,依然可以得到 ababmodφ(m)+φ(m)(modm)
4. 命题: a 为合数的情况,该式成立。

证明:

  • 只证 a 拆成两个素数的幂的情况,大于两个的用数学归纳法可证。设 a=a1a2, 其中 ai=piki ,而 ai 的循环长度为 si
    slcm(s1,s2) ,由于 s1|φ(m),s2|φ(m) ,那么 lcm(s1,s2)φ(m) ,所以 sφ(m)r=max(riki)max(ri)φ(m)
    r,sφ(m) 的关系,依然可以得到 ababmodφ(m)+φ(m)(modm) 。证毕。

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;
}

5. 引用资料

[0] Number Theory —— H_W_Y

[1] 欧拉定理 & 费马小定理 —— OI Wiki

posted @   FAKUMARER  阅读(61)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示