「学习笔记」欧拉函数及其证明

Before#

耗时一整天,打草纸写了近 4 页,才终于把所有的基本性质与公式用公式推出来,希望对你有帮助,可以点个赞吗?(期待+疲劳+无力)

定义#

对于整数 n,小于等于 n 中的数中与 n 互质的数的个数,记作 φ(n)
例如: φ(8)=4[1,8] 中,与 8 互质的数为 1,3,5,7,有 4

计算通式及证明#

φ(n)=n×(11p1)×(11p2)×(11pn)
(n=p1k1×p2k2××pnkn)
这个的证明过程太麻烦,我用的容斥来证明的,没学的话,先记住这个,所有的减去不互质的就是互质的!


我们来一步一步探究
我们先设 n=p1p2(p1p2),我们将 n 看作是一个 [1,n] 的区间,将区间平均分为 p2 段,每段长 p1,在每一段中,只有最后一个数不与 p1 互质(即 p1,2p1,3p1,),共有 p2 段,即有 p2 个数不与 p1 互质,同理,有 p1 个数不与 p2 互质
到这里,如果你认为不与 p1p2 互质的数的个数为 p1+p2,那你就成功的错了,如果你把每个不与 p1p2 互质的数全列出来,你会发现,np1p2,被加了两遍,所以不与 p1p2 互质的数的个数应该为 p1+p21,那么,φ(n)=p1p2p1p2+1,进行化简可以得到 φ(n)=(p11)(p21)=φ(p1)φ(p2)=n(11p1)(11p2)


我们来进一步探究
n=p1p2p3(p1p2p3),还是将 n 看作是 [1,n] 的区间,不与 p1 互质的数有 p2p3 个,不与 p2 互质的数有 p1p3 个,不与 p3 互质的数有 p1p2 个,当然,这里面有重复的,我们发现,p1p2p1p3p2p3 的倍数都被加了 2 遍,即多加了一遍,(为什么?拿 p1p2 举例子,在平均分成 p1 段时加了一遍,在平均分成 p2 段时又加了一遍),p1p2p3p1 加了 3 遍,即多加了 2 遍,我们先减去 p1p2p1p3p2p3 多出来的,即 p1p2+p1p3+p2p3np1p2np1p3np2p3=p1p2+p1p3+p2p3p3p2p1,再之后我们在减去 p1p2p3 多的两遍就行了,对吧?错了!,仔细看这个式子,当我们减去 p3,即 p1p2 的倍数时,p1p2p3 也是 p1p2 的倍数,被减了一,其他的同理,所以现在,p1p2p3 减了 3,而它原来就只加了 3 遍,所以现在 p1p2p3 相当于没加,我们还要再 +1,即式子为 p1p2+p1p3+p2p3p3p2p1+1φ(n)=p1p2p3p1p2p1p3p2p3+p3+p2+p11

φ(n)=p1p2p3p1p2p1p3p2p3+p3+p2+p11=p3(p1p2p1p2+1)(p1p2p1p2+1)=(p31)(p1p2p1p2+1)=(p31)(p2(p11)(p11))=(p31)(p21)(p11)=n(11p1)(11p2)(11p3)


其实到这里,你可能就发现规律了,如果没有,继续往下看,如果已经发现了,可以跳过这一部分
再进一步探究
n=p1p2p3p4
先写出最初的有重复的式子 p2p3p4+p1p3p4+p1p2p4+p1p2p3
每种变量加入的次数:
p1p2p1p3p1p4p2p3p2p4p3p4:加入了 2
p1p2p3p1p2p4p1p3p4p2p3p4:加入了 3
p1p2p3p4:加入了 4
再写出去重后的式子:
p2p3p4+p1p3p4+p1p2p4+p1p2p3np1p2np1p3np1p4np2p3np2p4np3p4+np1p2p3+np1p2p4+np1p3p4+np2p3p4np1p2p3p4
约分得:
p2p3p4+p1p3p4+p1p2p4+p1p2p3p3p4p2p4p2p3p1p4p1p3p1p2+p4+p3+p2+p11

ϕ(n)=p1p2p3p4p2p3p4p1p3p4p1p2p4p1p2p3+p3p4+p2p4+p2p3+p1p4+p1p3+p1p2p4p3p2p1+1=p4(p1p2p3p2p3p1p3p1p2+p3+p2+p11)(p1p2p3p2p3p1p3p1p2+p3+p2+p11)=(p41)(p1p2p3p2p3p1p3p1p2+p3+p2+p11)=(p41)(p31)(p21)(p11)=n(11p1)(11p2)(11p3)(11p4)


这是一步新的探索,n=p12p2
我们发现,p1 带了一个平方,但问题不大,还是按照之前的方法来计算,将 n 看作 [1,n]
不与 p1 互质的数的个数为 p1p2
在这里,虽然 p1 是带了平方,但是如果再用 p1 来划分求不互质的个数,结果是一样的,所以没有这个必要再求一遍
不与 p2 互质的数的个数为 p12
老样子,还是有重复,但这一次,重复的就不只是 p11p2 了,我们列举出这些数来看一下
不与 p1 互质的数:p1,2p1,3p1,,p2p1,,2p2p1,p1p2p1
不与 p2 互质的数:p2,2p2,3p2,,p1p2,,2p1p2,p1p1p2
发现了吗?重复的数都是 p1p2 的倍数,而这个倍数,有 np1p2=p1
所以,式子为:p1p2+p12p1

φ(n)=p12p2p1p2p12+p1=p1(p1p2p2p12+p)=p1(p11)(p21)=p12p2(p11p1)(p21p2)=n(11p1)(11p2)


通过上面我们的一步步推导,我们会发现,只有两个变量组成的变量(p1p2p1p3 之类的,抱歉我不会描述,先姑且称它为二元变量吧QWQ,其他的以此类推)会在计算答案时多加 1 次,三元变量多加 2 次,四元变量多加 3 次,根据规律,我们可以推测得五元变量多加 4 次,六元变量多加 5 次……
同时,我们还可以发现,在式子中(这里的式子是求不与 n 互质的数的个数,不是求 φ(n)),二元变量前面都是 ,三元变量前面是 +,四元变量前面是 ,我们可以以此类推,五元变量前面是 +,六元变量前面是 ……
通过我们最后推得的式子以及带指数的变量的计算,我们可以推测 φ(n)=n(11p1)(11p2)(11p3)(11pm)(n=p1k1p2k2p3k3p4k4pmkm)


性质及证明#

以下性质 p 均为素数
1 φ(p)=p1
证明:这个其实挺好理解的,p 为素数,它的因子只有 1p,所以,大于 0 小于 p 的数都与 p 互质,总共有 p1 个数,所以 φ(p)=p1
2 φ(i×p)=p×φ(i)(pi)
证明:

pi,pi,pii=pk×a1k1×a2k2×a3k3×ankn()i×p=pk+1×a1k1×a2k2×a3k3×anknφ(n)=n×(11p1)×(11p2)×(11pn)()(n=p1k1×p2k2××pnkn)φ(i×p)=p×i×(11p)×(11a1)×(11a2)×(11an)i=pk×a1k1×a2k2×a3k3×anknφ(i)=i×(11p)×(11a1)×(11an)φ(i×p)=p×φ(i)()

3 φ(i×p)=(p1)×φ(i)(pi)
证明:

ppipii=a1k1×a2k2×a3k3×ankn,p=p1i×p=p1×a1k1×a2k2×a3k3×anknφ(i×p)=i×p×(11p)×(11a1)×(11a2)××(11an)=(p1)×[i×(11a1)×(11a2)××(11an))φ(i)=i×(11p)×(11a1)×(11an)φ(i×p)=(p1)×φ(i)

推论、引理#

1φ(p×q)=φ(p)×φ(q)(pq)
这个的证明其实上面已经证过了,也可以用上面的性质 3 继续往下推一步即可

φ(p×q)=(p1)×φ(q)φ(p)=p1φ(p×q)=φ(p)×φ(q)

2φ(pa)=(p1)×pa1
证明: φ(pa)=(p1)×pa1=papa1
这里我们可以这么理解,我们将区间 [1,pa] 平均分成 pa1 段,每段长 p,在每段中,只有最后一个数不与 p 互质(这些数就是 p,2p,3p),因此,在 [1,pa] 上,有 pa1 个数不与 p 互质,即 apap1 个,所以 φ(pa)=(p1)×pa1=papa1

欧拉线性筛#

线性筛,又叫欧拉筛,我们利用欧拉函数的性质,再配合线性筛,可以线性求出每个数的 φ 值。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

inline ll read() {
	ll x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

const int N = 1e7 + 5;

int n, cnt;
ll phi[N], prime[N];
bool inp[N];

int main() {
	n = read();
	for (int i = 2; i <= n; ++ i) {
		if (!inp[i]) {
			prime[cnt ++] = i;
			phi[i] = i - 1;
		}
		for (int j = 0; j < cnt && i * prime[j] <= n; ++ j) {
			inp[i * prime[j]] = 1;
			if (!(i % prime[j])) {
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			else {
				phi[i * prime[j]] = phi[i] * phi[prime[j]];
			}
		}
	}
	for (int i = 2; i <= n; ++ i) {
		printf("%lld ", phi[i]);
	}
	return 0;
}

作者:yifan0305

出处:https://www.cnblogs.com/yifan0305/p/17038484.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

转载时还请标明出处哟!

posted @   yi_fan0305  阅读(198)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示