数论函数和筛法学习笔记
数论函数指定义域为正整数的函数,比如常见的 \(\varphi,\mu\) 等。
一些定义
积性函数:\(\gcd(a,b)=1\) 时 \(f(ab)=f(a)f(b)\)。
完全积性函数:\(f(ab)=f(a)f(b)\)(区别在于不要求互质)。
加性函数:\(f(a) + f(b) = f(ab)\)。
数论函数的加法:\((f+g)(x)=f(x)+g(x)\),即对应的点的值相加。
数论函数的数乘:\((c\cdot f)(x)=c \cdot f(x)\),即对应的点的值相加。
下面是一些常见的数论函数:
- \(\varphi(n) = \sum_{i=1}^{n}[\gcd(n,i)=1]\),即小于等于 \(n\) 的数字中和 \(n\) 互质的数的个数。
- \(\text{id}(n) = n\),恒等函数。
- \(\text{1}(n) = 1\),常数函数。
- \(\epsilon (n) = [n=1]\),单位函数。
- \(\mu(n) = \left\{\begin{matrix} 1 & n=1\\ 0 & \exists d > 1,d^2 \mid n\\ -1 & \text{otherwise} \end{matrix}\right.\),莫比乌斯函数。
下面我们介绍筛法,可以得到 \(1 \sim n\) 内的某个积性函数的值。
埃氏筛
很暴力的想法,枚举 \(2 \sim n\) 之间的所有数字,若这个数字没有被标记过,则视为其是一个质数,并用其去标记它的所有倍数。
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
p[++tot] = i;
for (int j = i * 2; j <= n; j += i)
vis[j] = 1;
}
}
我们给出这个算法的时间复杂度:\(O(n \ln \ln n)\),证明见下。
因为 \(n\) 以内的质数个数约为 \(\dfrac{n}{\ln n}\) 个,所以我们可以认为一个数字 \(x\) 有 \(\dfrac{1}{\ln x}\) 的概率是质数,然后求期望。
可得:
\[\begin{aligned} &\int_{2}^{n} \dfrac{1}{\ln x} \cdot \dfrac{n}{x} \cdot dx\\ =& n \int_{2}^{n} \dfrac{1}{x \ln x} \cdot dx \\ =& n \int_{2}^{n} \dfrac{1}{x \ln x} \cdot d(\ln x) \cdot x &(a)\\ =& n \int_{2}^{n} \dfrac{1}{\ln x} \cdot d(\ln x)\\ =& n \int_{2}^{n} \dfrac{1}{\ln x} \cdot d(\ln \ln x) \cdot \ln x\\ =& n \int_{2}^{n} \cdot d(\ln \ln x)\\ =& n \ln \ln n\\ \end{aligned}\]其中标注 \((a)\) 的那一步是因为 \(\dfrac{d(\ln x)}{dx} = \dfrac{1}{x}\)。
线性筛
实际代码中用的更多的是线性筛,这可以在 \(O(n)\) 的时间复杂度内求出很多积性函数。
对比埃氏筛,我们可以发现线性筛实际上只保证了一件事:每个数只被最小的质因子删去,埃氏筛之所以慢是因为很多数字被重复标记了。
for (int i = 2; i <= n; i++) {
if (!vis[i]) p[++tot] = i;
for (int j = 1; j <= tot && p[j] * i <= n; j++) {
vis[i * p[j]] = 1;
if(i % p[j] == 0) break;
}
}
我们之所以能保证其复杂度,关键在于中间那个 break 语句,这使得每个数只被最小的质因子删去,解释见下。
假设我们现在在筛掉 \(i\times p_j\) 这个合数,因为我们要求一个数只能被它最小的质因子筛去,不断枚举 \(p_j\) 就是在找这个最小质因子,假如 \(p_j | i\),是不是意味着 \(i\) 里面一定有 \(p_j\)?
假如 \(i\) 没有其他因子,那么也就意味着循环本该结束,break 就无所谓。
但是假如其中还有别的非平凡因子,那就意味着 \(p_j\) 一定不是最小的质因子,而后面更大的 \(p_j\) 就更没有可能是了,所以退出。
线性筛赋予了我们在 \(O(n)\) 的时间内得到很多积性函数的能力,下面是一些常见函数的线性筛方法。
欧拉函数
考虑在筛出素数的同时计算每个数的欧拉函数值。
首先根据定义当 \(i\in \text{Prime}\) 时, \(\varphi (i)=i - 1\)。
由唯一分解定理,\(n = \prod_{i=1}^{s}p_i^{k_i}\),那么我们认为有 \(\varphi (n)=n \prod_{i=1}^{s} \left ( 1-\dfrac{1}{p_i} \right )\)。下面给出证明。
考虑到欧拉函数是积性函数,那么我们有 \(\varphi(n) = \prod_{i=1}^{s}\varphi(p_i^{k_i})\)。
而 \(\varphi(p^{k}) = p^{k-1}(p-1)\),这是因为 \(p^k\) 中除了 \(\dfrac{p^k}{p} = p^{k-1}\) 个 \(p\) 的倍数外都和 \(p^k\) 互质。所以得到了:
\[\begin{aligned} \varphi(n) &= \prod_{i = 1}^{s}\varphi(p_i^{k_i}) \\ &= \prod_{i = 1}^{s}p_i^{k_i-1}(p_i-1)\\ &= \prod_{i = 1}^{s}p_i^{k_i}(1-\dfrac{1}{p_i})\\ &= n\prod_{i = 1}^{s}(1-\dfrac{1}{p_i})\\ \end{aligned}\]
考虑当我们标记一个数为合数的时候,在 \(p_j \nmid i\) 时也就意味着两者互质 \(\varphi (i\times p_j)=\varphi (i)\varphi (p_j)\)。
否则,我们考虑欧拉函数的计算式:\(\varphi (n)=n \prod_{i=1}^{s} \left ( 1-\dfrac{1}{p_i} \right )\)。现在我们考虑 \(i\) 和 \(p_j\),显然 \(i\) 中的质数种类就是最后的质数种类,那么 \(\varphi(i\times p_j)=p_j \times i\times \prod\left ( 1-\dfrac{1}{p} \right )=p_j \times \varphi(i)\)。
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
p[++tot] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= tot && p[j] * i <= n; j++) {
vis[i * p[j]] = 1;
if(i % p[j] == 0) {
phi[i * p[j]] = phi[i] * p[j];
break;
} else {
phi[i * p[j]] = phi[i] * (p[j] - 1);
}
}
}
莫比乌斯函数
回顾一下莫比乌斯函数的定义:\(\mu(n) = \left\{\begin{matrix} 1 & n=1\\ 0 & \exists d > 1,d^2 \mid n\\ -1 & \text{otherwise} \end{matrix}\right.\)。
也许你并不知道为啥莫比乌斯函数要这么定义,但是没有关系,这会在下文提到,现在我们只需要快速筛出 \(\mu\) 即可。
对于质数,根据定义,\(\mu = -1\)。
然后考虑不能整除,也就是多了一个 \(p_j\) 的质因子,\(\mu(i\times p_j) = -\mu(i)\)。
能整除时,也就意味着出现了平方因子,\(\mu = 0\)。
mu[1] = 1; //定义如此
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
p[++tot] = i;
mu[i] = -1;
}
for (int j = 1; j <= tot && p[j] * i <= n; j++) {
vis[i * p[j]] = 1;
if (i % p[j] == 0) {
mu[i * p[j]] = 0;
break;
} else {
mu[i * p[j]] = -mu[i];
}
}
}
通过上面的了解,我们可以总结出线性筛的基本方法,就是要能快速得到 \(i \in \text{Prime}\) 时的值,同时通过其定义得到其他值。
我们不妨再以线性筛出 \(i^k\) 为例,感受这一方法。
在 \(i \in \text{Prime}\) 的时候,我们使用快速幂算出 \(i^k\),然后对于 \(i \times p_j\),其值就是 \(i^k \times p_j^k\)。
狄利克雷(Dirichlet)卷积
若数论函数 \(h(n) = \sum_{d \mid n} f(d)g(\dfrac{n}{d})\)
则记为 \(h = f * g\),表示 \(h\) 是 \(f,g\) 狄利克雷巻积后的结果。
狄利克雷巻积具有交换律,结合律和分配律。
【证明 1】狄利克雷巻积具有交换律
\[f * g = \sum_{d \mid n} f(d)g(\dfrac{n}{d}) = \sum_{d' \mid n} g(d)f(\dfrac{n}{d'}) = g * f \]
【证明 2】狄利克雷巻积具有结合律
\[\begin{aligned} (f * g) * h & = \sum_{d|n}(\sum_{i \mid d} f(i)g(\dfrac{d}{i}))h(\dfrac{n}{d}) \\ & = \sum_{i|n}f(i)(\sum_{k \mid \frac{n}{i}}g(k)h(\dfrac{\frac{n}{i}}{k}))\\ &=f*(g*h) \end{aligned}\]
【证明 3】狄利克雷巻积具有分配律
\[\begin{aligned} (f+g)*h&=\sum_{d|n}(f+g)(d)h(\dfrac{n}{d}) \\ &=\sum_{d|n}f(d)h(\dfrac{n}{d}) + \sum_{d|n}g(d)h(\dfrac{n}{d})\\ &=f*h+g*h \end{aligned}\]
我们还可以得到一些狄利克雷巻积的性质。
【性质 1】\(\epsilon * f = f\)
\[\epsilon * f = \sum_{d|n}[d=1]f(\dfrac{n}{d})=f \]所以这个是狄利克雷巻积的单位元。
然后可以定义其逆元:\(f * g = \epsilon\),则 \(f,g\) 互为对方的逆元。
【性质 2】两个积性函数的狄利克雷巻积还是积性函数。
设 \(f,g\) 是两个积性函数,\(h = f * g\)。
我们现在设 \(\gcd(a, b) = 1\),\(h(a) = \sum_{d|a}f(d)g(\dfrac{a}{d}),h(b) = \sum_{d|b}f(d)g(\dfrac{b}{d})\)
\[\begin{aligned} h(a)h(b) &= \sum_{d_1|a}f(d_1)g(\dfrac{a}{d_1})\sum_{d_2|b}f(d_2)g(\dfrac{b}{d_2})\\ &= \sum_{d|ab}f(d)g(\dfrac{ab}{b} )\\ &= h(ab) \end{aligned}\]
狄利克雷前缀和
对于一个函数 \(f\),我们计算 \(g = \text{1} * f\),得到 \(g = \sum_{d|n}f(d)\),这个被称为狄利克雷前缀和。
朴素的计算方法是 \(O(n \ln n)\) 的,但是如果将其看作一个对于每个质数的高维前缀和便可仿照埃氏筛做到 \(O(n \ln \ln n)\)。
for (int i = 2; i <= n; i ++) {
for (int j = 1; j <= tot && p[j] * i <= n; j ++) {
a[i * p[j]] += a[i];
}
}
数论分块
一言以蔽之:对于值相同的位置一起算答案。
在解释之前,我们要证明一个东西,在 \(l\) 一定时,使
满足的最大的 \(r\) 为 \(\left \lfloor\dfrac{n}{\left \lfloor\dfrac{n}{l} \right \rfloor} \right \rfloor\)。
先翻译一下:对于一个块内值为 \(p=\left \lfloor\dfrac{n}{l} \right \rfloor\),则块的右端点最大为 \(\left \lfloor\dfrac{n}{p} \right \rfloor\)。
Proof.
考虑对于这个块内的每个 \(x\) 都有 \(\left \lfloor\dfrac{n}{x} \right \rfloor = p\),则 \(n=px+q(0\le q < n)\),所以 \(n\ge px\),\(x\le \dfrac{n}{p}\),又因为 \(x\) 为整数,所以 \(\max x=\left \lfloor\dfrac{n}{p} \right \rfloor\)。
整理一下我们得到了什么:对于 \(l\),我们知道了最大的 \(r\),也知道了这一段的某个相同的值,是不是就可以求和了呢?实际上这也就是其主要应用之一。
【例题 1】UVA11526:
求 \(\sum_{i=1}^{n} \left \lfloor \dfrac{n}{i} \right \rfloor\)。
应用上面的结论,可以得到每一段和每一段的值,直接求和即可。
for (int l = 1, r; l <= n; l = r + 1) {
r = min(n, n / (n / l));
sum += (r - l + 1) * (n / l);
}
代码非常简单。
但是我们还不知道它为什么是对的。换句话说,我们需要证明其复杂度,显然看到“分块”,你可以估测其复杂度为根号级别。
我们考虑 \(\left \lfloor \dfrac{n}{i} \right \rfloor\) 的取值,当 \(i\le\sqrt{n}\) 时,显然 \(\left \lfloor \dfrac{n}{i} \right \rfloor\) 至多有 \(\sqrt{n}\) 个取值。
当 \(i\ge \sqrt{n}\) 时,\(\left \lfloor \dfrac{n}{i} \right \rfloor \le \sqrt{n}\),显然也只有 \(\sqrt{n}\) 个取值。所以总取值至多在 \(2\sqrt{n}\),所以复杂度为 \(\sqrt{n}\) 级别,但是注意到这东西有一个 \(2\) 的常数,所以数论分块的常数是略大的。
【例题 2】P2261 [CQOI2007] 余数求和:
求 \(\sum_{i=1}^{n} k \bmod i\)。
我们考虑计算后面的式子,此时对于 \(l\le r\) 这一段,贡献为 \(\sum_{i=l}^{r}i\left \lfloor \dfrac{k}{i} \right \rfloor\),我们可以两个分别求和再相乘。
前面显然是一个等差数列求和,后面直接整除分块做即可。
注意一个 corner case,\(n>k\) 时,有除数为 \(0\) 需要特判。
由此可见,数论分块能处理的问题还能拓展到求 \(\sum_{i=1}^{n} f(i)\left \lfloor \dfrac{n}{i} \right \rfloor\) 的问题。
【例题 3】P3935 Calculating:
这题能给我们一个重要的结论。
首先意识到 \(f(i)\) 就是 \(i\) 的因数个数。显然我们只要求出 \(\sum_{i=1}^{n}f(i)\) 就能求出答案。
这个东西怎么求呢?你可以先看一下 P1403 [AHOI2005] 约数研究。发现:
大概解释一下,对于 \(1\) ,会作为每个 \(n=1k\) 的数的因数,对于 \(2\) ,会作为每个 \(n=2k\) 的数的因数,总共有 \(\left \lfloor \dfrac{n}{2} \right \rfloor\) 个这样的数字。依次类推。
然后可以用数论分块解决。
【二维整除分块】P2260 [清华集训2012] 模积和:
首先容斥一下,把 \(i=j\) 的在最后减掉即可。
显然可以数论分块,但是不要忘记还要容斥减掉 \(i=j\) 的情况,考虑那个怎么算,不妨假设 \(n\le m\)。
前三项显然平凡,直接数论分块即可,考虑计算 \(\sum_{i=1}^{n} i^2\left \lfloor \dfrac{n}{i} \right \rfloor \left \lfloor \dfrac{m}{i} \right \rfloor\),这是一个多维的整除分块,我们不妨先看看去掉 \(i^2\) 后怎么做。
想想我们到底是按什么在分块?是值相同,那么假设当前的 \(l\) 是确定的,也就是说 \(r_i\) 是确定的,那么我如果要能够把这些项一起算,也就是说要找出最大的 \(r\) 使得其对所有数都成立,显然,\(R=\min r_i\)。这个结论也可以拓展到多维。
然后平凡。考虑加上 \(i^2\) 项,我们发现 \(\sum_{i=1}^{n}i^2=\dfrac{n(n+1)(2n+1)}{6}\),于是计算区间的平方和就行了。
给出代码实现:
for (int l = 1, r; l <= n; l = r + 1) {
r = min(n / (n / l), m / (m / l));
sum += (f(r) - f(l - 1)) * (n / l) * (m / l);
}
实际上,结合莫比乌斯反演,整除分块还有很大的应用空间。
莫比乌斯反演
再次回顾莫比乌斯函数,\(\mu(n) = \left\{\begin{matrix} 1 & n=1\\ 0 & \exists d > 1,d^2 \mid n\\ -1 & \text{otherwise} \end{matrix}\right.\)。
我们指出 \(\sum_{d|n}\mu(d)=\epsilon(n)\),即 \(\mu * 1 = \epsilon\)。
证明
设 \(n = \prod_{i=1}^k p_i^{c_i},m=\prod_{i=1}^k p_i\),根据定义有 \(\sum_{d|n}\mu(d)=\sum_{d|m}\mu(d)\),因为有平方因子的项都是 \(0\),不会对答案造成贡献。\(\sum_{d|m}\mu(d) = \sum_{i=0}^{k}\binom{k}{i}(-1)^{i}=(1-1)^k\),只有 \(k=0\) 即 \(n=1\) 的时候才为 \(1\),否则为 \(0\)。
这说明了一件事情,\(\mu\) 和 \(1\) 是在狄利克雷巻积下的逆元,如果说卷上 \(1\) 是狄利克雷前缀和,那么卷上 \(\mu\) 就是差分。
而这还可以引出莫比乌斯反演,\([n=1]=\epsilon(n)=\sum_{d|n}\mu(d)\)。
一般我们用的最多的就是 \([\gcd(i,j)=1]=\epsilon(n)=\sum_{d|\gcd(i,j)}\mu(d)\)。
【例题 1】P2522 [HAOI2011] Problem b
首先我们可以差分一下,每次求 \(\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k]\)
然后可以整除分块求解。
杜教筛
这是一种可以低于线性时间得到积性函数前缀和的方法。
首先我们的目标是求出 \(S(n) = \sum_{i=1}^{n}f(i)\),为了求解 \(S(n)\),我们构造一个数论函数 \(g\)。
这样的话我们有:
如果能够快速计算 \((f*g)(i)\),和 \(g(i)\) 的前缀和,那么就可以快速求得 \(g(1)S(n)\)。
下面我们尝试使用杜教筛来计算常见的 \(\mu,\varphi\) 的前缀和。
求莫比乌斯函数的前缀和
\(S(n) = \sum_{i=1}^n \mu(i)\),因为我们知道 \(\mu * 1 = \epsilon\),那么不防直接构造 \(g = 1\),代入上面的式子可以得到:
然后直接整除分块递归求解即可。
求欧拉函数的前缀和
根据欧拉函数的定义,我们知道 \(\sum_{i=1}^{n}\sum_{j=1}^{n}[\gcd(i,j)=1] = 2\varphi(n) - 1\),然后求出 \(\sum_{i=1}^{n}\sum_{j=1}^{n}[\gcd(i,j)=1]\) 即可。
这是莫比乌斯反演的经典式子,我们可以得到:
然后直接整除分块,利用之前算 \(\mu\) 前缀和的方法即可。
当然也可以不这么算,有一种效率更高的计算方法:利用 \(\varphi * 1 = \mathrm{id}\)。
【例题】P7277 平凡点滴
首先做一些基础的转化。
后面的可以使用杜教筛求解,关键在于前面的 \(f\) 函数的前缀和。这个 \(g(n)\) 很烦,但是很小,我们考虑去枚举,记 \(S(n) = \sum_{i=1}^{n}f(i)\)。
发现这个等于不好处理,那么我们设 \(H(n, x) = \sum_{i=1}^{n}[g(i)\le x] i^k\),原式后面就可以化成 \(H(n, x) - H(n, x - 1)\)。
考虑使用容斥计算 \(H(n,x)\),我们钦定有若干个质因子幂次大于 \(x\),那么就是 \(\sum_{i=1}^{n}\mu(i)\left ( i^{x+1} \right )^k\sum_{j=1}^{\frac{n}{i^{x+1}}}j^k\),发现后面是个自然数幂和的形式,前面的的 \(i\) 枚举到 \(\sqrt[x+1]{n}\) 即可。
于是 \(H\) 可以暴力计算,然后此题就解决了。

浙公网安备 33010602011771号