积性函数与反演
-
一些定义
首先我们定义迪利克雷卷积 \(f \times g (n) = \sum\limits_{d \mid n} f(d)g(\frac{n}{d})\).
那么接下来定义积性函数 \(f\),对于 \(\forall a, b, a \perp b\) 则有 \(f(a) f(b) = f(ab)\).
然后是我们熟悉的 \(\mu\) 函数,对于 \(\forall n = p_1 ^ {a_1} p_2 ^ {a_2} \cdots p_k ^ {a_k}\)
根据积性函数的定义,很容易得到 \(\mu\) 是一个积性函数。
下面是我们更熟悉的 \(\varphi\) 函数,\(\varphi(n)\) 即 \(1 \sim n\) 中与 \(n\) 互质的数的个数。对于 \(\forall n, m, n \perp m\),考虑构造一个 \(n \times m\) 的方阵,第 \(i\) 行第 \(j\) 列为 \((i - 1) \times m + j\) 显然这里会包含 \(1 \sim n \times m\) 中的所有数。接下来考虑每一列,因为 \(\gcd(i * m + j, m) = gcd(j, m)\) 因此每一列要么全部与 \(m\) 互质,要么都不与 \(m\) 互质,则有 \(\varphi(m)\) 列与 \(m\) 互质。再考虑每一列,因为 \(\gcd(n, m) = 1\), 所以对于每一行 \(i \times m + j\) 会构成一个模 \(n\) 的完全剩余系,因此有 \(\varphi(n)\) 行与 \(n\) 互质,因此有 \(\varphi(nm) = \varphi(n) \times \varphi(m)\),也就证明了 \(\varphi\) 函数的积性性质。
我们有一种直接计算 \(\varphi(n)\) 的方法,对于 \(\forall n = p_1 ^ {a_1} p_2 ^ {a_2} \cdots p_k ^ {a_k}\)
根据积性函数的性质,\(\varphi(n) = \prod\limits_{i = 1} ^ k \varphi(p_i ^ {a_i})\),特殊地我们有 \(\varphi(p ^ k) = (1 - \frac{1}{p})p ^ k\) 乘起来即可证明。
上面我们提到了单独计算 \(\mu, \varphi\) 函数的方法,但这样效率并不高,因为我们每计算一次都需要分解质因数,因此计算一次的复杂度为 \(O(\sqrt{n})\),有没有什么更优复杂度的做法呢?事实上是有的,就是强无敌的线性筛。
回忆一下我们在线性筛质数的时候是用 \(i \times prime_j\) 去筛掉质数,注意到如果 \(i \perp prime_j\) 根据积性函数的理论我们可以通过 \(i, prime_j\) 的函数值来计算 \(i \times prime_j\) 的函数值,具体地下面给出筛 \(\mu\) 函数和 \(\varphi\) 函数的代码
iprime[1] = mu[1] = 1;
rep(i, 2, M){
if(!iprime[i]) prime[++tot] = i, mu[i] = -1;
for(int j = 1; j <= tot && i * prime[j] <= M; ++j){
iprime[i * prime[j]] = 1;
if(i % prime[j] == 0){ mu[i * prime[j]] = 0; break;} // 根据定义显然这里有两个以上的素因子
mu[i * prime[j]] = -mu[i];
}
}
iprime[1] = phi[1] = 1;
rep(i, 2, M){
if(!iprime[i]) prime[++tot] = i, phi[i] = i - 1;
for(int j = 1; j <= tot && i * prime[j] <= M; ++j){
iprime[i * prime[j]] = 1;
if(i % prime[j] == 0){ phi[i * prime[j]] = phi[i] * prime[j]; break;} //对于那些和 i 互质的数扩大 1-prime[j] 倍还是会和 i 互质,而其他数还是不会和 i 互质
phi[i * prime[j] = phi[i] * phi[prime[j]];
}
}
-
下面我们步入反演的时代
定义 \(I(x) = 1, id(x) = x, \epsilon(x) = [x = 1]\)
那么我们有 \(\mu \times I(n) = \sum\limits_{d \mid n} \mu(d) = [n = 1] = \epsilon(n)\)
其中倒数第二步是 \(\mu\) 函数的性质,首先可以知道存在有两个及以上质因子的数对答案没有贡献,那么我们只需要考虑仅包含单个质因子乘积的数,将每个质因子抽象成一个球,那么我们要算的就是从中拿出偶数个球的方案和奇数个球的方案之差。根据二项式定理 \((x + y) ^ n = \sum\limits_{k = 0} ^ n \dbinom{n}{k} x ^ k y ^ {n - k}\) 令 \(x = 1, y = -1\) 有 \(\sum\limits_{k = 0} ^ n \dbinom{n}{k} (-1) ^ k = 0\) 即奇数和偶数的拿球方案相同,因此 \(\sum\limits_{d \mid n} \mu(d) = [n = 1]\).
因此可以得到 \(\mu \times I = \epsilon\)
另一个可以得到的类似式子是 \(\varphi \times I(n) = \sum\limits_{d \mid n} \varphi(d) = n = id(n)\)
倒数第二步也是 \(\varphi\) 函数的一个性质,注意到一个柿子 \(\sum\limits_{d \mid n} \sum\limits_{i = 1} ^ n [\gcd(i, n) = d] = n\) 等价于 \(\sum\limits_{d \mid n} \sum\limits_{i = 1} ^ {\lfloor \frac{n}{d} \rfloor} [\gcd(i, \frac{n}{d}) = 1] = n\) 即 \(\sum\limits_{d \mid n} \varphi(d) = n\).
因此可以得到 \(\varphi \times I = id\)
由上面两个得到的性质还可以得到 \(id \times \mu = \varphi(n)\) 证明将第二条性质两边乘上 \(\mu\) 即可。
讲了这么多下面正式开始反演。
若有 \(f = g \times I\) 则有 \(g(n) = f \times \mu\) 证明类似于上面的性质三。
这就是大名鼎鼎的莫比乌斯反演,一般我们构造一组 \(f, g\) 满足上述关系,\(f\) 也可以很好算出来,然后通过计算出 \(g(n)\) 来求出想要的答案。
下面我们看一道莫比乌斯反演的经典应用
下面我们默认 \(n \le m\).
按照套路我们先枚举 \(\gcd\)
按照套路除去 \(d\)
一般我们在这里使用上面提到的 \(\mu\) 函数的性质,而不使用更高级作用更广的莫反。
即
提前枚举 \(k\)
令 \(T = kd\)
提前枚举 \(T\)
首先我们考虑后面那个东西怎么算,令 \(f(n) = \sum\limits_{d \mid n} \mu(d) \times \frac{n}{d}\) 由 \(\mu\) 函数的性质容易证明 \(g\) 是个积性函数,通过类似地筛 \(\mu\) 函数的方法,我们只需要考虑两个特殊部分的值如何算就可以线性筛出该积性函数,一个是 \(n\) 为质数的情况,那么此时 \(f(n) = n - 1\),第二个是 \(p \mid i, p \in prime\) 的情况,显然如果我们同时选取两个或以上 \(p\) 那么对答案的贡献一定为 \(0\),对于其他的情况对答案的贡献都会是原来的 \(p\) 倍,那么我们有 \(f(i \times p) = f(i) \times p\).那么我们就只需要修改线性筛的两个地方即可。实际上有 \(f(n) = \sum\limits_{d \mid n} \mu(d) \times \frac{n}{d} = \mu \times id = \varphi(n)\) 因此 \(f\) 即 \(\varphi\).
除此以外还有一种更加通用的线性筛积性函数的方法,我们只需要知道如何快速求 \(x\) 为质数的答案和 \(x = p ^ k\) 的答案或 \(p ^ k\) 如何从 \(p ^ {k - 1}\) 推过来即可。放上代码可以更好理解。
// low为最小质因子所占次幂
iprime[1] = f[1] = 1;
rep(i, 2, M){
if(!iprime[i]) prime[++tot] = i, f[i] = Dec(Qpow(i, k), 1), low[i] = i; // 快速求出为质数的答案
for(int j = 1; j <= tot && i * prime[j] <= M; ++j){
iprime[i * prime[j]] = 1;
if(i % prime[j] == 0){
low[i * prime[j]] = low[i] * prime[j]; // 更新low
if(low[i] == i) f[i * prime[j]] = Inc(Qpow(i * prime[j], k), Mul(Qpow(i, k), Mod - 1)); // i = p ^ k
else f[i * prime[j]] = Mul(f[i / low[i]], f[low[i] * prime[j]]); // 此时 i / low[i] 与 low[i] * prime[j] 一定互质
break;
}
f[i * prime[j]] = Mul(f[i], f[prime[j]]), low[i * prime[j]] = prime[j];
}
}
现在我们筛出了 \(f\) 的前缀和,直接枚举就可以 \(O(n)\) 计算了,但这样显然不优,实际上我们有一种做法能做到 \(O(\sqrt{n})\) 它就是大名鼎鼎的整除分块。
我们会发现这样一个事实,如果我们需要求 \(\sum\limits_{i = 1} ^ n \lfloor \frac{n}{i} \rfloor\) 中间会有很多数是相同的,而这些数我们可以一起算掉这样可以大大节省复杂度。假设当前我们知道一段相同的数开始的位置 \(l\),那么对于结尾的位置 \(r\) 我们有 \(\lfloor \frac{n}{l} \rfloor \le \frac{n}{r}\) 则 \(r \le \frac{n}{\lfloor \frac{n}{l} \rfloor}\) 这样我们就可以算出结尾的位置了,下次开头的位置就会是 \(r + 1\),这样不断算下去即可。下面分析一下复杂度,实际上这里的复杂度只与 \(\lfloor \frac{n}{i} \rfloor\) 的取值个数有关,当 \(i \le \sqrt{n}\) 时,显然 \(\lfloor \frac{n}{i} \rfloor\) 的取值小于等于 \(\sqrt{n}\),当 \(i > \sqrt{n}\) 时 \(\lfloor \frac{n}{i} \rfloor \le \sqrt{n}\) 取值个数也不超过 \(\sqrt{n}\),因此数论分块的复杂度为 \(O(\sqrt{n})\).
回到本题,会发现 \(\lfloor \frac{n}{T} \rfloor,\lfloor \frac{m}{T} \rfloor\) 的取值也用很多是相同的,用上面的整除分块复杂度就可以做到 \(O(\sqrt{n})\).
再看一道另一种类型的题
其中 \(f\) 为斐波那契数列
下面默认 \(n \le m\).
同样的套路,我们先枚举 \(d = \gcd(i, j)\)
右上角那坨和上面那题就类似了,最终可以推导得
令 \(T = dk\).
枚举 \(T\)
右上角的指数可以整除分块,但貌似括号里的东西不能线性筛?数据范围比较小,暴力筛出来枚举倍数即可。
再来一道题
按照套路枚举 \(d = \gcd(i, j)\)
括号内把 \(d\) 除去,注意考虑改变 \(i, j\) 枚举范围后对答案的影响。
利用 \(\mu\) 函数的性质
提前枚举 \(k\)
令 \(T = dk, S(n) = \sum\limits_{i = 1} ^ n i\)
太丑了拉两个 \(d\) 进来
提前枚举 \(T\)
最后面那一坨太熟悉了即
为了能整除分块我们把 \(T ^ 2\) 和 \(\varphi(T)\) 想办法一起预处理
现在问题变成如何求 \(S(n) = \sum\limits_{i = 1} ^ n i ^ 2 \varphi(i)\)。显然是可以线性筛的,但出题人十分毒瘤 \(n \le 10 ^ {10}\).这个时候就有了一个黑科技 \(--\) 杜教筛
杜教筛是这样一个流程,首先如果我们要求 \(S(n) = \sum\limits_{i = 1} ^ n f(i)\) 其中 \(f\) 为积性函数。考虑构造另一个积性函数 \(g\),现在假设 \(g\) 已知,那么 \(f \times g = \sum\limits_{i = 1} ^ n \sum\limits_{d \mid i} g(d) f(\frac{i}{d})\),根据莫反的套路我们先枚举 \(d\),\(f \times g = \sum\limits_{d = 1} ^ n g(d) \sum\limits_{d \mid i} f(\frac{i}{d}) = \sum\limits_{d = 1} ^ n g(d) \sum\limits_{i = 1} ^ {\lfloor \frac{n}{d} \rfloor} f(i)\) 写的好看一点即 \(f \times g = \sum\limits_{i = 1} ^ n g(i) S(\lfloor \frac{n}{i} \rfloor)\),特殊地,当 \(i = 1\) 时 \(\lfloor \frac{n}{i} \rfloor = n\),于是我们考虑将 \(i = 1\) 情况单独拉出来,就有 \(g(1) S(n) = f \times g - \sum\limits_{i = 2} ^ n g(i) S(\lfloor \frac{n}{i} \rfloor)\),于是有\(S(n) = \frac{f \times g - \sum\limits_{i = 2} ^ n g(i) S(\lfloor \frac{n}{i} \rfloor)}{g(1)}\) 假设 \(f \times g\) 和 \(g\) 的前缀和可以很快算出来,那么我们就只需要调用 \(S(\lfloor \frac{n}{i} \rfloor)\) 然后数论分块,因为 \(i\) 是从 \(2\) 开始枚举的,很明显可以感受到每次 \(n\) 除了 \(2\),感觉这样递归复杂度会更优,事实上可以证明这个复杂度是 \(O(n ^ {\frac{3}{4}})\) 的,然后如果我们线性预处理出某一部分的答案,那么最后递归时就能节省不少时间,经过检验可以预处理 \(n ^ {\frac{2}{3}}\) 的答案,这样复杂度最终可以做到 \(O(n ^ {\frac{2}{3}})\)。但是杜教筛的复杂度是需要记忆化来保证的,但记忆化时的下标可能会超过我们空间能承受的范围,我们可以选择 \(\rm STL\) 的 哈希表 \(\rm unordered\ map\) \(O(1)\) 查询。当然还有另一种更高明的方法,回忆一下之前的整除分块,我们会发现如果 \(x \le \sqrt{n}\) 那么 \(x\) 一定会被提前预处理掉,如果 \(x > \sqrt{n}\) 那么每次我们继续调用的 \(S\) 值都是 \(\frac{n}{x} \le \sqrt{n}\) 这样我们只需要开一个 \(sum\) 来记录 \(\frac{n}{x}\) 的值就可以 \(O(1)\) 查询了。
前面我们都是在已知 \(g\) 的情况下讨论的,具体地,我们现在来算 \(S(n) = \sum\limits_{i = 1} ^ n \mu(i)\) 的值,根据前面 \(\mu\) 函数的性质,我们有 \(\mu \times I = \epsilon\) 于是我们构造 \(g = I\),会发现杜教筛中 \(f \times g = 1\),那么 \(g\) 的前缀和就是 \(x\) 这样就可以杜教筛了。那么对于 \(S(n) = \sum\limits_{i = 1} ^ n \varphi(i)\),利用 \(\varphi\) 函数的性质 \(\varphi \times I = id\) 可以类似地算。下面帖一下筛 \(\mu\) 函数的部分。
int solve(int x){
if(x <= M) return smu[x];
if(Smu[n / x]) return Smu[n / x];
int ans = 1;
for(int l = 2, r = 0; l <= x && r <= x; l = r + 1){
r = x / (x / l);
ans -= (r - l + 1) * solve(x / l);
}
return Smu[n / x] = ans;
}
再回到本题,我们需要算 \(S(n) = \sum\limits_{i = 1} ^ n i ^ 2 \varphi(i)\),我们令 \(f(n) = n ^ 2 \varphi(n)\),那么假设我们知道 \(g\),则 \(f \times g = \sum\limits_{i = 1} ^ n \sum\limits_{d \mid i} d ^ 2 \varphi(d) g(\frac{i}{d})\)。注意到 \(\sum\limits_{d \mid i} \varphi(d) = i\),我们想办法把 \(d ^ 2\) 变成与 \(d\) 无关的数拉出来就可以让 \(\varphi\) 用这条性质算出来,那么 \(f \times g\) 就可以很快算出来了。那么我们令 \(g(n) = n ^ 2\) 就刚好可以约掉分母 \(d\),原式化为 \(\sum\limits_{i = 1} ^ n i ^ 2 \sum\limits_{d \mid i} \varphi(d) = \sum\limits_{i = 1} i ^ 3 = (\frac{n \times (n + 1)}{2}) ^ 2\).\(g\) 的前缀和即 \(\frac{n \times (n + 1) \times (2n + 1)}{6}\),这样就可以快速杜教筛了。