今天学长给我们教了数论选讲,把里面的精髓提出来浅谈记录一下。顺便附上机房一位神仙对本文的注解
什么是数论?
摘自 百度:
数论是纯粹数学的分支之一,主要研究整数的性质。整数可以是方程式的解。有些解析函数中包括了一些整数、质数的性质,透过这些函数也可以了解一些数论的问题。
数论被高斯成为“数学皇后”,是一大必不可少的分支。
前置导入
积性函数
积性函数代指一类函数。若函数 f 满足对于两个互质的数 a,b,f(a)×f(b)=f(ab),则 f 为积性函数。
简单而言,对于一个函数 f(n),若 ∀a,b∈N+&gcd(a,b)=1,f(a)×f(b)=f(ab),那么 f 是一个积性函数。
常见的积性函数有 φ,μ,id 等等,下面将会提到一部分。
部分数学符号选讲
有高中数学基础的可以直接跳过。
∏ 表示连乘,举例为:∏i=1Nxi ,意思是 x1×x2×x3×⋯×xN。
∑ 表示累加,举例为:∑i=1Nxi ,意思是 x1+x2+x3+⋯xN。
∀ 表示“所有的”,∃ 表示“存在”,& 表示“且”。
∈ 表示属于,a∈A 表示元素 a 属于集合 A。N+ 表示正整数集合,N 表示自然数集合(非负整数集合)。
⌊ba⌋ 表示对 ba 的值向下取整。
gcd(a,b) 表示 a 和 b 的最大公约数,lcm(a,b) 为最小公倍数。
∣ 表示整除,a∣b 表示 b 是 a 的倍数,∤ 表示不整除,a∤b 表示 b 不是 a 的倍数。
诸如 [a=b] (即方括号内放一个关系式)的形式的东西表示:若方括号内的式子为真,则该式子值为 1,反之则为 0。举个例子就可以简单地说明:
[a<b]={1(a<b)0(a⩾b)
其他未在此处出现的符号后文均会有说明。
关于本文
- 后文出现的 p 均表示质数。
- 互质的定义为两个数的最大公约数为 1,本文将 00 视为 1,1 不是质数,也不视为完全平方数(注:一般认为 00 没有意义,1 是完全平方数)。
- 如果没有特殊说明,变量范围均为正整数范围内。
- 文章没有网站上的例题(实际上文中例题只有一个且只能展现莫比乌斯反演知识),如有需要自找题目。
欧拉函数选讲
欧拉函数的符号是 φ,我们记 φ(n) 表示在 [1,n] 的正整数中,与 n 互质的数的个数,特别地,φ(1)=1。
欧拉函数的性质
欧拉函数是一个积性函数,具体地证明过程较为复杂,这里不多讨论。
欧拉函数有一些很美妙的性质。首先,根据定义,结合常识,因为质数与小于它的任何正整数都互质,所以有 φ(p)=p−1。类似地,对于一个质数的幂 piki,因为一共有 piki 个数,其中只有 piki−1 个数与其有不为 1 的公因数(也就是 pi 的倍数个数为那么多),因此我们还可以得出:φ(pk)=pk−pk−1。这个式子做一个简单的变形,就可以得到:φ(pk)=pk×(1−p1)。
下面我们来证明另一个性质:φ(n)=n×∏(1−pi1):显然对于任何一个 n,一定可以将其拆分为 ∏piki 的形式。考虑将这些东西全部乘起来,由于 p1k1,p2k2,p3k3⋯ 一定互质,又因为欧拉函数是积性函数,因此这些东西乘起来就是 φ(n)。因此有:
φ(n)=∏φ(piki)
φ(n)=∏[piki×(1−pi1)]
因为 ∏[piki×(1−pi1)]=∏piki×∏(1−pi1),而前文提到 ∏piki=n,因此最终得到:
φ(n)=n×∏(1−pi1)
当然除此之外还有许多有趣的性质。如果你尝试算一算一个数 n 的所有因数的欧拉函数值,就会发现它们加起来恰好等于 n。翻译成数学语言如下:∑d∣nφ(d)=n。
一个简单的证明方法,就是你写下分母为 n 的所有分数 na(1⩽a⩽n):n1,n2,n3,⋯nn,然后给每个数约个分,约分后的分数中,分母就是所有 n 的因数,分子就是所有与分母互质的数。它们一共有 n 个,因此得证。
如果无法理解的话,可以以 n=6 举个例子:61,62,63,64,65,66,约分之后变成 61,31,21,32,65,11。分子就是所有与其分母互质的数,分母就是 n 的所有约数。而显然这里一共有 6 个数,因此 ∑d∣6φ(d)=6。
欧拉函数和一个数有几个和它互质的数有关,如果给定一个 n,并统计出了 [1,n] 之间所有与 n 互质的数有哪些,你就会发现这些数字的和恰好等于 2n×φ(n)。这里还需要引入一个定理:
对于任意正整数 i,n(i<n),若 gcd(i,n)=1,则有 gcd(n−i,n)=1。
因此我们列出 n 的所有约数的时候,一定是最小的和最大的加起来为 n,第二小的和第二大的加起来为 n,第三小的和第三大的加起来为 n……一共有 2φ(n) 个这样的数对,每对的和为 n,因此总的和为 2n×φ(n)。
因此欧拉函数的常用性质有:
- 是积性函数。对于互质的两个数 a,b,有 φ(a)×φ(b)=φ(ab)。
- 对于质数 p,φ(p)=p−1。
- 对于质数 p,φ(pk)=pk−pk−1=pk×(1−p1)。
- 记 n=∏piki,其中 pi 为质数,ki∈N+,有 φ(n)=n×∏(1−pi1)。
- ∑d∣nφ(d)=n。
- [1,n] 中所有与 n 互质的数之和为 2n×φ(n)。
此外还有一些不常用的性质,例如:
- 若 2∤n,φ(2×n)=φ(n)。
- 若质数 p 满足 p∣n,p2∣n,则 φ(n)=φ(pn)×p。
- 若质数 p 满足 p∣n,p2∤n,则 φ(n)=φ(pn)×(p−1)。
不过第二个和第三个是线性筛求欧拉函数需要的式子,值得注意。
欧拉函数的运用延伸
我们常常遇到对一个答案取模运算的问题。如果计算中又出现了除法,我们就不得不进行求逆元的操作。通常我们会使用费马小定理。而费马小定理,其实就是欧拉定理的一种特殊形式。
对于互质的两个数 a,m,有 aφ(m)≡1(modm)。(欧拉定理)
特别地,若 m 为质数(记为 p),有 ap−1≡1(modp)。(费马小定理)
对于求一个数的欧拉函数,显然只要分解其质因数,套用性质求解即可,当这个 n 较大时显然瓶颈在分解质因数,因此认为其复杂度为 O(n) 的。但是如果我需要求 [1,n] 的欧拉函数,显然 O(nn) 的做法过于暴力而不可取。
类比线性筛素数的做法,运用性质,可以得出如下的代码:
inline void GetPhi(int n){ // 求 [1,n] 的欧拉函数,顺便筛素数
memset(isPrime, 1, sizeof(isPrime));
// isPrime 是 bool,所以可以直接用 1 memset
isPrime[1] = 0, phi[1] = 1;//1不是素数,phi(1)=1
for(register int i = 2; i <= n; ++i){
if(isPrime[i]){// 是质数
Prime[++cnt] = i, // prime 统计质数,cnt 为质数个数
phi[i] = i - 1;
}
for(register int j = 1; j <= cnt && i * Prime[j] <= n; ++j){
// i*Prime[j] 不必超上限 n
isPrime[ i * Prime[j] ] = 0;
if(i % Prime[j] == 0){ // i中也含有Prime[j]这个因子
phi[ i * Prime[j] ] = phi[i] * Prime[j];
break;
}
else phi[ i * Prime[j] ] = phi[i] * (Prime[j] - 1);
}
}
}
莫比乌斯函数选讲
莫比乌斯函数的符号是 μ。μ(n) 的值计算方法如下:若 μ(n) 存在一个不为 1 的完全平方数的因子,则 μ(n)=0,否则,记 μ(n) 有 m 个不同的质因子,则 μ(n)=(−1)m。
莫比乌斯函数的性质
莫比乌斯函数是积性函数,简单做一个其积性的证明:
对于互质的两个数 a,b,若其任意一个有完全平方数的因子,则它们一定满足以下两个中至少一个: μ(a)=0,μ(b)=0 。显然 a×b 一定也含有完全平方数因子,因此 μ(a×b)=0=μ(a)×μ(b)。特别地,μ(1)=1。
若其有公共的质因子,则不满足 a,b 互质的条件,情况不成立。则将 a,b 含有的质因子个数表示为 ma,mb,则 ma+mb 是 a×b 的因子个数。枚举 ma,mb 的奇偶性验证即可。
除此之外,如果你求出 n 的所有因子的莫比乌斯函数值,你会发现当 n=1 时,它们的和为 1,否则为 0。转化为数学语言可以大概写成如下式子:∑d∣nμ(d)=[n=1]。
显然我们可以不用考虑那些 μ 值为 0 的数。因此对于有 k 个质因数的数字 n,由其中 r 个质因数相乘可以得到的因数个数,就是 μ 值不为 0 的因数个数。从 k 个数选 r 个,明显是组合数,一共有 Ckr 个。
考虑到 r 的奇偶性决定这些因子的 μ 值的正负。根据定义可以得出:
d∣n∑μ(d)=i=0∑k(−1)i×Cki
根据二项式定理,有:(x+y)k=∑i=0kCki×xi×yk−i。(注意这里的 k 不是前面假设的 k 个数)将 x=−1,y=1 代入:
0k=i=0∑kCk1×(−1)i×1k−i=i=0∑k(−1)i×Cki
当 n=1 时,k=n−1=0,有原式值为 00=1,否则原式值为 0。证毕。
以上就是莫比乌斯函数常用的一些性质。实际上还有部分性质,但是涉及到了后文写的内容,所以在这里姑且放着不提。
莫比乌斯函数的运用延伸
因为莫比乌斯函数一般都会用于莫比乌斯反演,也是后面提到的内容。因此这里只能简单提一下莫比乌斯函数的计算。同于欧拉函数,对于一个数 n,计算 μ(n) 只需要将其分解质因数,然后根据定义简单判断即可,单个数的计算是 O(n) 的。重点来看多个数的情况。
发现莫比乌斯函数的线性递推依然可以建设在线性筛的基础上。所以有如下代码:
void GetMu(int n){ // 求 [1,n] 的莫比乌斯函数,顺便筛素数
memset(isPrime, 1, sizeof(isPrime));
// isPrime 是 bool,所以可以直接用 1 memset
isPrime[1] = 0, mu[1] = 1;//1不是素数,mu(1)=1
for(register int i = 2; i <= n; ++i){
if(isPrime[i]){// 是质数
Prime[++cnt] = i, // prime 统计质数,cnt 为质数个数
mu[i] = -1;
}
for(register int j = 1; j <= cnt && i * Prime[j] <= n; ++j){
// i*Prime[j] 不必超上限 n
isPrime[ i * Prime[j] ] = 0;
if(i % Prime[j] == 0){ // i中也含有Prime[j]这个因子
mu[i*prime[j]]=0;
break; // 这里不要更新 mu 值!!
}
else mu[ i * Prime[j] ] = mu[i] * (-1);
}
}
}
狄利克雷卷积与莫比乌斯反演
对于两个函数 f,g,以及某个函数 h,若对于 ∀n∈N+,有 h(n)=∑d∣nf(d)×g(dn),则记作 f∗g=h。其中 h 是 f 和 g 的狄利克雷卷积。
狄利克雷卷积
狄利克雷卷积满足交换律、结合律、分配律。(分配律即 (f+g)∗h=f∗h+g∗h)。
此外还有一个重要的性质:两个积性函数的狄利克雷卷积也是积性函数。
专门出现一种称为“单位元”的函数 ε。“单位元”函数为 ε=[n=1]。对于任意函数 f,有 f∗ε=f。
除此之外,狄利克雷卷积和欧拉函数、莫比乌斯函数都有一些相关的性质。假设我们定义一个函数 1,对于任何一个数 n,有 1(n)=1。还有一种函数 id,对于任何一个数 n,id(n)=n。
先来探究 1 函数的性质,容易发现若卷积的一个函数是 1(不妨设为 g 的那个函数),意味着 f 乘上的数都是 1,也就是它本身,因此有:
f∗1=d∣n∑f(d)
右边这一块已经见到过很多次了,结合欧拉函数和莫比乌斯函数的性质,可以得出:
μ∗1=d∣n∑μ(d)=ε=[n=1]
φ∗1=id
将第二个等式左右两边同时乘上一个 μ,有:φ∗1∗μ=id∗μ,将第一个等式代入,得到 φ∗ε=id∗μ,又因为单位元矩阵乘任何函数,函数不变。因此得到一个重要的结论,印证着 φ,μ,id 的关系:
μ∗id=φ
同时简单变形还可以得到欧拉函数和莫比乌斯函数两者的关系:
φ(n)=d∣n∑μ(d)×dn
莫比乌斯反演
在狄利克雷卷积的基础上,接着来探究这样一个性质:
记函数 F,f 满足 F(n)=∑d∣nf(d),则有 F∗μ=f。
推导过程也相对简单,因为 F(n)=∑d∣nf(d),得到 F=1∗f。等式两边同时乘上一个 μ,有 F∗μ=1∗μ∗f=ε∗f=f。
因此可以得出莫比乌斯反演的式子:
F(n)=d∣n∑f(d)⇒f(n)=d∣n∑F(d)∗μ(dn)
F(n)=n∣d∑f(d)⇒f(n)=n∣d∑F(d)∗μ(nd)
莫比乌斯反演有什么用呢?事实上它的作用就是化简我们的推导式子,可以让一个本来不是很容易求解的函数,转换到一个容易求解的函数上进行运算。最后放上一道用上了莫比乌斯反演性质优化算法的例题作为烂尾:
例题:给定 n,m,k,求有多少个数对 (x,y),满足 1⩽x⩽n,1⩽y⩽m,且 gcd(x,y)=k。
不难得出我们需要求的结果其实就是 ∑i=1n∑j=1m[gcd(i,j)=k]。
求一对数的最大公约数为 k 的相对难处理,我们可以将其转化为求最大公约数为 1的情况。如果一对数 (i,j),其中 i⩽⌊kn⌋,j⩽⌊km⌋,且 gcd(i,j)=1,不难得出 i×k⩽n,j×k⩽m,且有 gcd(i,j)=k。
进一步利用莫比乌斯反演的性质:∑d∣nμ(d)=[n=1],所以总的答案转化为:
Ans=i=1∑⌊kn⌋j=1∑⌊km⌋[gcd(i,j)=1]=i=1∑⌊kn⌋j=1∑⌊km⌋d∣gcd(i,j)∑μ(d)=d=1∑⌊kmin(n,m)⌋⌊kdn⌋⌊kdm⌋μ(d)
这样就可以 O(n) 地求解这个问题了,不难发现如果不用上莫比乌斯反演或其性质,即使 gcd 可以 O(1) 算出来,整体复杂度也是 O(n3) 的,整体优化十分可观。