本文应sharpland男神要求转载一下这位大佬的欧拉函数博客!!
原文传送门
定义
在数论中,对正整数n,欧拉函数是小于等于n的数中与n互质的数的数目。并且用符号 φ(n) 表示一个整数的欧拉函数。例如 φ(8)=4 。 φ(1)=1 。
一些欧拉函数的性质
性质一
对于一个质数n,
φ(n)=n−1
。
证明:因为n是质数。
性质二
若
n=pk
,则
φ(n)=pk−pk−1=(p−1)×pk−1
证明:
因为除了p的倍数以外,其他数都跟n互质。
性质三
当
gcd(n,m)=1
时,
φ(nm)=φ(n)∗φ(m)
证明:
φ(n)
是积性函数。
性质四
设
n=pk11×pk22×……×pkmm
,则
φ(n)=n×(1−1p1)×(1−1p2)×……×(1−1pm)
证明:
根据性质二
当然也可以用容斥的想法去理解。
性质五
欧拉定理:对于互质的整数
a,m
有
aφ(m)≡1(modm)
证明:
这小于n且与n互质的集合时
Z
显然
令集合
S={a×p1modn,a×p2modn…a×pφ(n)modn}
。
因为:
- 因为
a
与
n 互质, pi 与 n 互质,所以a×pi 与 n 互质,所以a×p1modn∈Z - 若
i≠j
,那么
a×pimodn≠a×pjmodn
反证:
假如 a×pimodn=a×pjmodn ,设 a×pi=ki×n+b
那么
a×pia×(pi−pj)=ki×n+b=kj×n+b=n×(ki−kj)
因为 a 与n 互质,即 n|(pi−pj) ,不成立。
所以 S=Z
由此我们可以列出等式:
a×p1×a×p2…×a×pφ(n)aφ(n)≡p1×p2×…pφ(n)(modn)≡1(modn)
延伸:
费马定理:如果正整数 a 与p 互质,则 ap−1≡1(modp) 。
证明:由性质一可得 φ(p)=p−1 ,代入欧拉定理即可。
性质六
设小于n的所有与n互质的数的和为
Sum,Sum=n×φ(n)2
证明:
首先证明一个结论:如果
gcd(n,i)=1
则
gcd(n,n−i)=1
。
反证法:
如果存在
k≠1
使
gcd(n,n−i)=k
那么
(n−i)modk=0
,
nmodk=0
可以得到
imodk=0
,即
gcd(n,i)=k
,也就是说如果
gcd(n,i)=1
,那么
gcd(n,n−i)
就不能大于1。
那么就可以得知与n互质的数都是成对存在的,并且和为n,那么就可以得出
Sum=n×φ(n)2
的公式。
性质七
首先
p
是个质数。如果
证明:
对于第一个结论我们只需证明
gcd(n,m)=1
可以得出
gcd(n,m+n)=1
即可。
反证法:
假设
gcd(n,m+n)=b(b≠1)
。设
n+m=k1b,m=k2b
所以 gcd(n,m) 至少等于 b 。
得证。
对于第二个结论,我们可知由于
性质八
直接给式子吧…
n=∑d|nφ(d)
根据上面那条式子可以继续推点显而易见的东西 。
反演一下, φ(n)=∑d|nμ×nd
信息学中的应用
应用一:线筛 φ 函数
这个算法可以让我们从
O(n)
的时间得出
φ(1)
到
φ(n)
的值。
首先我们要用到几条上面提到的:性质一,性质七。
那么根线筛素数的原理一样(积性函数)我们只需根据欧拉函数的性质来进行线筛。
//YxuanwKeith
void Getphi(int Max) {
phi[1] = 1;
for (int i = 2; i <= Max; i ++) {
if (!Flag[i]) {
phi[i] = i - 1; // i是质数,第一种情况。
pri[++ pri[0]] = i;
}
for (int j = 1; j <= pri[0]; j ++) {
if (1ll * i * pri[j] > Max) break;
Flag[i * pri[j]] = 1; //筛质数。
if (i % pri[j] == 0) {
phi[i * pri[j]] = phi[i] * pri[j];//(i % pri[j] = 0),第二种情况
break;
}
phi[i * pri[j]] = phi[i] * (pri[j] - 1); //(i % pri[j] != 0),第三种情况
}
}
}
应用二: O(n√) 得到 φ(n)
直接根据性质四,
O(n√)
的枚举
n
的所有质因子,然后直接套用公式算,如果
//YxuanwKeith
long long Getphi(long long n) {
long long phi = n;
for (long long i = 2; i * i <= n; i ++) {
if (n % i == 0) {
phi /= i;
phi *= i - 1;
while (n % i == 0) n /= i;
}
}
if (n != 1) phi /= n, phi *= n - 1;
return phi;
}
应用三:杜教筛求 φ 的前缀和
即求
∑ni=1φ(i)
,
n≤1010
51nod题目链接
由于本文着重讨论欧拉函数的性质,所以就不细讲杜教筛相关内容,有兴趣的可以通过下面的blog了解:
杜教筛
基本原理:假设我们要计算
S(n)=∑ni=1f(i)
根据杜教筛的应用,设 f(i)=φ(i) ,我们要找到一个函数 g(i) 使得 g(i) 的前缀和和 f(i)×g(i) 的前缀和都很好求。根据性质八,不难发现 f(i)×l=id(l函数满足各项都为1,id函数满足id(i)=i)
设 ϕ(n)=∑ni=1φ(i) ,根据杜教筛:
然后递推进去算就可以了,直接这样算是 O(n34) 但是由于 φ 是积性函数,可以预处理出前 n23 的 ϕ 然后再做杜教筛,复杂度就优化成了 O(n23)
//YxuanwKeith
//51nod1239
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const int MAXN = 5e6 + 5, MAXM = 1e6 + 5;
const int Mo = 1e9 + 7;
LL n, que[MAXM];
int m, num, pri[MAXN], sum[MAXN], phi[MAXN], ids[MAXM], idl[MAXM], s[MAXM], inv[MAXN];
bool flag[MAXN];
int power(int x, int y) {
int ans = 1;
for (; y; y >>= 1, x = 1ll * x * x % Mo)
if (y & 1) ans = 1ll * ans * x % Mo;
return ans;
}
void prepare() {
phi[1] = 1;
for (int i = 2; i < MAXN; i ++) {
if (!flag[i]) pri[++ pri[0]] = i, phi[i] = i - 1;
for (int j = 1; j <= pri[0] && 1ll * i * pri[j] < MAXN; j ++) {
int x = i * pri[j];
flag[x] = 1;
if (i % pri[j] == 0) {
phi[x] = phi[i] * pri[j];
break;
}
phi[x] = phi[i] * (pri[j] - 1);
}
}
for (int i = 1; i < MAXN; i ++) sum[i] = (sum[i - 1] + phi[i]) % Mo;
}
int main() {
scanf("%lld", &n);
prepare();
m = sqrt(n);
for (LL l = 1; l <= n; l ++) {
LL d = n / l, r = n / d;
que[++ num] = d;
if (d <= m) ids[d] = num; else idl[l] = num;
l = r;
}
int inv = power(2, Mo - 2);
for (int i = num; i; i --) {
LL x = que[i];
if (x < MAXN) s[i] = sum[x]; else {
int y = x % Mo;
s[i] = 1ll * y * (y + 1) % Mo * inv % Mo;
for (LL l = 2; l <= x; l ++) {
LL p = x / l, r = x / p;
p = (p <= m) ? ids[p] : idl[n / p];
(s[i] -= 1ll * (r - l + 1) * s[p] % Mo) %= Mo;
l = r;
}
}
}
printf("%d\n", (s[1] + Mo) % Mo);
}
另外还有一些欧拉函数的变形也可以通过杜教筛来算:
1.
f(i)=φ(i)×i
,
f(i)×id=id2
这个可以扩展到 f(i)=φ(i)×ik , f(i)×idk=idk+1