Before#
耗时一整天,打草纸写了近 4 页,才终于把所有的基本性质与公式用公式推出来,希望对你有帮助,可以点个赞吗?(期待+疲劳+无力)
对于整数 n,小于等于 n 中的数中与 n 互质的数的个数,记作 φ(n)
例如: φ(8)=4 在 [1,8] 中,与 8 互质的数为 1,3,5,7,有 4 个
计算通式及证明#
φ(n)=n×(1−1p1)×(1−1p2)…×(1−1pn)
(n=pk11×pk22×…×pknn)
这个的证明过程太麻烦,我用的容斥来证明的,没学的话,先记住这个,所有的减去不互质的就是互质的!
我们来一步一步探究
我们先设 n=p1p2(p1⊥p2),我们将 n 看作是一个 [1,n] 的区间,将区间平均分为 p2 段,每段长 p1,在每一段中,只有最后一个数不与 p1 互质(即 p1,2p1,3p1,…),共有 p2 段,即有 p2 个数不与 p1 互质,同理,有 p1 个数不与 p2 互质
到这里,如果你认为不与 p1p2 互质的数的个数为 p1+p2,那你就成功的错了,如果你把每个不与 p1、p2 互质的数全列出来,你会发现,n 即 p1p2,被加了两遍,所以不与 p1p2 互质的数的个数应该为 p1+p2−1,那么,φ(n)=p1p2−p1−p2+1,进行化简可以得到 φ(n)=(p1−1)(p2−1)=φ(p1)φ(p2)=n(1−1p1)(1−1p2)
我们来进一步探究
设 n=p1p2p3(p1⊥p2⊥p3),还是将 n 看作是 [1,n] 的区间,不与 p1 互质的数有 p2p3 个,不与 p2 互质的数有 p1p3 个,不与 p3 互质的数有 p1p2 个,当然,这里面有重复的,我们发现,p1p2、p1p3、p2p3 的倍数都被加了 2 遍,即多加了一遍,(为什么?拿 p1p2 举例子,在平均分成 p1 段时加了一遍,在平均分成 p2 段时又加了一遍),p1p2p3、p1 加了 3 遍,即多加了 2 遍,我们先减去 p1p2、p1p3、p2p3 多出来的,即 p1p2+p1p3+p2p3−np1p2−np1p3−np2p3=p1p2+p1p3+p2p3−p3−p2−p1,再之后我们在减去 p1p2p3 多的两遍就行了,对吧?错了!,仔细看这个式子,当我们减去 p3,即 p1p2 的倍数时,p1p2p3 也是 p1p2 的倍数,被减了一,其他的同理,所以现在,p1p2p3 减了 3,而它原来就只加了 3 遍,所以现在 p1p2p3 相当于没加,我们还要再 +1,即式子为 p1p2+p1p3+p2p3−p3−p2−p1+1,φ(n)=p1p2p3−p1p2−p1p3−p2p3+p3+p2+p1−1
φ(n)=p1p2p3−p1p2−p1p3−p2p3+p3+p2+p1−1=p3(p1p2−p1−p2+1)−(p1p2−p1−p2+1)=(p3−1)(p1p2−p1−p2+1)=(p3−1)(p2(p1−1)−(p1−1))=(p3−1)(p2−1)(p1−1)=n(1−1p1)(1−1p2)(1−1p3)
其实到这里,你可能就发现规律了,如果没有,继续往下看,如果已经发现了,可以跳过这一部分
再进一步探究
n=p1p2p3p4
先写出最初的有重复的式子 p2p3p4+p1p3p4+p1p2p4+p1p2p3
每种变量加入的次数:
p1p2、p1p3、p1p4、p2p3、p2p4、p3p4:加入了 2 次
p1p2p3、p1p2p4、p1p3p4、p2p3p4:加入了 3 次
p1p2p3p4:加入了 4 次
再写出去重后的式子:
p2p3p4+p1p3p4+p1p2p4+p1p2p3−np1p2−np1p3−np1p4−np2p3−np2p4−np3p4+np1p2p3+np1p2p4+np1p3p4+np2p3p4−np1p2p3p4
约分得:
p2p3p4+p1p3p4+p1p2p4+p1p2p3−p3p4−p2p4−p2p3−p1p4−p1p3−p1p2+p4+p3+p2+p1−1
ϕ(n)=p1p2p3p4−p2p3p4−p1p3p4−p1p2p4−p1p2p3+p3p4+p2p4+p2p3+p1p4+p1p3+p1p2−p4−p3−p2−p1+1=p4(p1p2p3−p2p3−p1p3−p1p2+p3+p2+p1−1)−(p1p2p3−p2p3−p1p3−p1p2+p3+p2+p1−1)=(p4−1)(p1p2p3−p2p3−p1p3−p1p2+p3+p2+p1−1)=(p4−1)(p3−1)(p2−1)(p1−1)=n(1−1p1)(1−1p2)(1−1p3)(1−1p4)
这是一步新的探索,n=p21p2
我们发现,p1 带了一个平方,但问题不大,还是按照之前的方法来计算,将 n 看作 [1,n]
不与 p1 互质的数的个数为 p1p2
在这里,虽然 p1 是带了平方,但是如果再用 p1 来划分求不互质的个数,结果是一样的,所以没有这个必要再求一遍
不与 p2 互质的数的个数为 p21
老样子,还是有重复,但这一次,重复的就不只是 p11p2 了,我们列举出这些数来看一下
不与 p1 互质的数:p1,2p1,3p1,…,p2p1,…,2p2p1,…p1p2p1
不与 p2 互质的数:p2,2p2,3p2,…,p1p2,…,2p1p2,…p1p1p2
发现了吗?重复的数都是 p1p2 的倍数,而这个倍数,有 np1p2=p1 个
所以,式子为:p1p2+p21−p1
φ(n)=p21p2−p1p2−p21+p1=p1(p1p2−p2−p21+p)=p1(p1−1)(p2−1)=p21p2(p1−1p1)(p2−1p2)=n(1−1p1)(1−1p2)
通过上面我们的一步步推导,我们会发现,只有两个变量组成的变量(p1p2、p1p3 之类的,抱歉我不会描述,先姑且称它为二元变量吧QWQ,其他的以此类推)会在计算答案时多加 1 次,三元变量多加 2 次,四元变量多加 3 次,根据规律,我们可以推测得五元变量多加 4 次,六元变量多加 5 次……
同时,我们还可以发现,在式子中(这里的式子是求不与 n 互质的数的个数,不是求 φ(n)),二元变量前面都是 −,三元变量前面是 +,四元变量前面是 −,我们可以以此类推,五元变量前面是 +,六元变量前面是 −……
通过我们最后推得的式子以及带指数的变量的计算,我们可以推测 φ(n)=n(1−1p1)(1−1p2)(1−1p3)…(1−1pm)(n=pk11pk22pk33pk44…pkmm)
性质及证明#
以下性质 p 均为素数
1、 φ(p)=p−1
证明:这个其实挺好理解的,p 为素数,它的因子只有 1 和 p,所以,大于 0 小于 p 的数都与 p 互质,总共有 p−1 个数,所以 φ(p)=p−1
2、 φ(i×p)=p×φ(i)(p∣i)
证明:
∵p∣i,且p为质数∴i是一个和数,p是i的一个质因子∴i=pk×ak11×ak22×ak33…×aknn(质因数分解)∴i×p=pk+1×ak11×ak22×ak33…×aknn∵φ(n)=n×(1−1p1)×(1−1p2)…×(1−1pn)(注意,这里只是欧拉函数的计算公式,与前面的证明过程中的变量无关)(这里n=pk11×pk22×…×pknn)∴φ(i×p)=p×i×(1−1p)×(1−1a1)×(1−1a2)×…(1−1an)∵i=pk×ak11×ak22×ak33…×aknn∴φ(i)=i×(1−1p)×(1−1a1)…×(1−1an)∴φ(i×p)=p×φ(i)(带入即可)
3、 φ(i×p)=(p−1)×φ(i)(p∤i)
证明:
∵p是质数,且p∤i∴p⊥i∵i=ak11×ak22×ak33…×aknn,p=p1∴i×p=p1×ak11×ak22×ak33…×aknn∴φ(i×p)=i×p×(1−1p)×(1−1a1)×(1−1a2)×…×(1−1an)=(p−1)×[i×(1−1a1)×(1−1a2)×…×(1−1an))∵φ(i)=i×(1−1p)×(1−1a1)…×(1−1an)∴φ(i×p)=(p−1)×φ(i)
推论、引理#
1、φ(p×q)=φ(p)×φ(q)(p⊥q)
这个的证明其实上面已经证过了,也可以用上面的性质 3 继续往下推一步即可
φ(p×q)=(p−1)×φ(q)∵φ(p)=p−1∴φ(p×q)=φ(p)×φ(q)
2、φ(pa)=(p−1)×pa−1
证明: φ(pa)=(p−1)×pa−1=pa−pa−1
这里我们可以这么理解,我们将区间 [1,pa] 平均分成 pa−1 段,每段长 p,在每段中,只有最后一个数不与 p 互质(这些数就是 p,2p,3p…),因此,在 [1,pa] 上,有 pa−1 个数不与 p 互质,即 ap−ap−1 个,所以 φ(pa)=(p−1)×pa−1=pa−pa−1
欧拉线性筛#
线性筛,又叫欧拉筛,我们利用欧拉函数的性质,再配合线性筛,可以线性求出每个数的 φ 值。
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下