「数论函数」学习笔记 积性函数 狄利克雷卷积 整除分块 莫比乌斯函数 欧拉函数 杜教筛
定义域为正整数,值域为整数的函数称为数论函数。OI中常用的数论函数有(mu),(varphi)等。
完全积性函数:(f(ab)=f(a)f(b))
一般积性函数:(f(ab)=f(a)f(b),a perp b)
常见的积性函数如下:
莫比乌斯函数 | (mu(n)) |
---|---|
欧拉函数 | (varphi(n)) |
单位函数 | ( ext{id}(n)=n) |
元函数 | (epsilon(n)=[n=1]) |
恒等函数 | (I(n)=1) |
约数个数 | $d(n)=sumlimits_{i=1}^n[i |
约数和 | $sigma(n)=sumlimits_{i |
狄利克雷卷积
两个函数(f,g)的狄利克雷卷积(t):
记为(t = f ast g)
一个重要的性质:两个积性函数的狄利克雷卷积仍为积性函数
整除分块
假如说我们要求解$$sumlimits_{i=1}^{n}left lfloor n over i ight floor$$
直接模拟是(O(n))的。而我们发现(left lfloor dfrac{n}{i} ight floor)在(i)相近时会有很多重复的值。整除分块的思想就是将所有重复的数值一起计算。
有结论(left lfloor dfrac{n}{i} ight floor .. left lfloor dfrac{n}{n/(n/i)} ight floor)的值都是相等的,而(left lfloor dfrac{n}{i} ight floor)总共有不超过(2sqrt{n})个取值。因此复杂度是(O(sqrt{n}))。
莫比乌斯函数
定义
考虑一个函数(F(n)=sumlimits_{d|n}f(d)),能否通过对(f)进行容斥得出(F)?其容斥系数满足什么特定规律吗?
我们发现(F)的定义其实是个狄利克雷卷积的形式。即(F=f ast I)
因此(f)即为(F)卷上“(I)的狄利克雷逆”。由此我们便定义这个容斥系数,也就是莫比乌斯函数(mu),为(I)的逆。即
或
莫比乌斯函数的性质
性质一
(mu)函数为积性函数。即
性质二
由此任意的莫比乌斯函数都可以表示为(mu(n)=prodlimits_{i} mu(p_i^{y_i})) (分解质因数)
(p^y)很特殊,根据之前的结论有(sumlimits_{d|p^y}mu(d)=0),因此(mu(1)+mu(p)+mu(p^2)+ cdots mu(p^y)=0)
由此猜测莫比乌斯函数值的性质:(mu(1)=1,mu(p)=-1),并且对于所有指数(y)大于(1)的,满足(mu(p^y)=0)
也就是:
这个结论是正确的。我们可以用二项式定理证明这样的性质满足莫比乌斯函数的定义:
(n>1)时,将(n)分解质因数得(n=p_1^{y_1} ast p_2^{y_2} ast ... ast p_k^{y_k})。任何一个质数的个数超过(1)时莫比乌斯函数值一定为(0),可以不管。我们只需要考虑有多少个质因数的指数都为(1)。因此有
线性筛
积性函数都可以由线性筛求得。代码如下:
inline void SieveMu(int n){
mu[1] = 1;
for(int i = 2; i <= n; ++i){
if(!b[i]){
prm[++tot] = i;
mu[i] = -1;
}
for(int j = 1; j <= tot && i*prm[j] <= n; ++j){
b[i*prm[j]] = 1;
if(i % prm[j] == 0){
mu[i*prm[j]] = 0;
break;
}else{
mu[i*prm[j]] = -mu[i];
}
}
}
}
莫比乌斯反演
根据莫比乌斯函数的定义,我们发现莫比乌斯函数具有如下的反演原理。
公式 1
公式 2
问题一
求$sumlimits_{i=1}^{n}sumlimits_{j=1}^{m }[gcd(i,j) = k], (n < m ) $
直接通过定义来变形:
可以使用整除分块(O(sqrt{n}))求解。
将(gcd)换到外面枚举是一个常用的(trick)。
问题二
求(sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}gcd(i,j),(n<m))
第一个(sum)可以用整除分块,第二个也是。于是复杂度为(O(n))。
我们还可以进一步优化——设(T=i cdot d),则有
后面部分(sumlimits_{d|T}dmu(dfrac{T}{d}))是一个狄利克雷卷积,是一个积性函数,我们可以在线性筛时筛出。然后直接整除分块就可以(O(sqrt{n}))完成求解了。
将两个数的乘积设做一个变量进行恒等变形也是一个常用(trick)。
欧拉函数
定义
对于一个正整数(n),小于(n)且与(n)互质的正整数个数记作(varphi(n)) 。
即
其中特殊定义(varphi(1)=1)
常用的欧拉函数值:(varphi(p)=p-1, varphi(p^k)=p^k-p^{k-1})
其中,欧拉函数也是积性函数。满足(varphi(nm)=varphi(n)varphi(m), n perp m),因此也可以通过线性筛求出。
既然这样,那么将(n)分解质因数得到(n=prodlimits_{i}p_{i}^{k_i}),则有(varphi(n)=prodlimits_{i}varphi(p_i^{k_i}))。
于是就得出了(varphi)的通项公式:
欧拉函数的性质
这个性质非常巧妙。这其实是一个真分数约分的过程。
约分后交换顺序得到
当然这个性质可以表示成狄利克雷卷积的形式:
也就是
那么也就得到了
即
杜教筛
杜教筛要解决的问题时在低于线性的复杂度下求出积性函数的前缀和。
即求
我们找另一个积性函数(g)去卷(f),令(h = f ast g)。
那么
我们要求的是(S(n)),因此考虑将它表示出来:
移项得到
这就是杜教筛的核心式子。这是一个递归式,如果我们能够快速求得(f ast g)以及(g)这两个函数的前缀和,那么就可以(O(n^{frac{2}{3}}))求出(S(n))。而难点就在于找出合适的(g)。
问题一
求出(S(n)=sumlimits_{i=1}^{n}mu(i))
关于(mu)的卷积,有(mu ast I = epsilon)。(epsilon)和(I)的前缀和都非常好求,因此我们选择(I)来作为(g)。
根据((3.1))可得
化简得
问题二
求出(S(n)=sumlimits_{i=1}^{n}varphi(i))
欧拉函数有性质((2.4):)(varphi ast I = ext{id})。因而还是选择(I)来作为(g)。
同理,根据((3.1))有
化简得
代码实现
这个递归式我们通过记忆化搜索来实现。通过map
来储存筛过的值。
为了提高效率,可以先用欧拉筛筛出(sqrt{n})以内的前缀和,防止杜教筛在小数据范围内递归次数太多。后面部分通过整除分块来实现。
int DuJiaoMu(int n){
if(n <= B) return smu[n];
if(mp_mu[n]) return mp_mu[n];
int res = 1;
for(int i = 2,j; i <= n; i = j+1){
j = n/(n/i);
res -= (j-i+1)*DuJiaoMu(n/i);
}
return mp_mu[n] = res;
}