参考了刘汝佳老师《算法艺术与信息学竞赛》。
离散变换与反演
有些时候,我们所求解问题的答案可以表示成一个类似前缀和的形式:\(f(x)=\sum a_ig(i)\)。
更多时候,\(g(x)\)是我们所需的答案,不易求出;而\(f(x)\)则可以通过另一种更好的方式求出来。如何根据\(f(x)=\sum a_ig(i)\)来推导出\(g(x)\)的解析式呢?这个反推的过程,我们可以叫做反演。我们用一个例子来具体说明。
我们已经用容斥原理得出了错排问题的答案,即在\(n\)个元素中的所有排列中,第\(i(1 \leq i \leq n)\)个元素不是\(i\)的排列数目\(D_n\)。现在我们来尝试用反演的方法。
我们反过来求:有且仅有\(k\)个元素处在正确位置的方案数为\(\dbinom{n}{k}D_{n-k}\),即剩余的\(n-k\)个元素不允许再排在原来的位置。
易知,所有排列里,一定存在\(0,1,\cdots,n\)个元素恰好排在其位置的方案。我们把他们加起来得到:
\[
P_n=n!=\sum_{k=0}^n \dbinom{n}{k}D_{n-k} \tag{*}
\]
反演(解出\(D_n\))得到:
\[
D_n=n!\sum_{r=0}^n{(-1)^r \frac{1}{r!}} \tag{**}
\]
为什么这样做是可行的呢?这是因为以下这个公式:
\[
\begin{aligned}
& a_n=\sum_{k=0}^n \dbinom{n}{k}b_k
\\ & b_n=\sum_{k=0}^n (-1)^{n-k}\dbinom{n}{k} a_k
\end{aligned}
\tag{1}
\]
这个式子叫做所谓的二项式变换。我们不妨把\((*)\)带入\((1)\)式检验:
\[
\begin{aligned}
& P_n=\sum_{k=0}^n \dbinom{n}{k}D_{n-k}=\sum_{k=0}^n\dbinom{n}{k}D_k
\\ & D_n=\sum_{k=0}^n (-1)^{n-k}\dbinom{n}{k} P_k = \sum_{k=0}^n (-1)^{n-k}\dfrac{n!}{(n-k)!}=n!\sum_{k=0}^n(-1)^k\frac{1}{k!}
\end{aligned}
\]
事实上,不仅只有二项式可以这样变换。变换需要满足以下条件。
设有两个多项式簇\(p_k(x),q_k(x),k=0,1,2,\cdots,n\),其中多项式\(p_i , q_i\)均是\(i\)次的如果它们满足:
\[
\begin{cases}
p_k(x)=\sum_{i=0}^k \alpha_{i,k}q_i(x)
\\q_k(x)=\sum_{i=0}^k \beta_{i,k}p_i(x)
\end{cases}
(k=0,1,2,\cdots,n)
\]
且系数满足以下正交性:$ \sum \alpha_{i,k}\beta_{k,j}= \delta_{j,k} = [j=k]$
则下列两式可以相互推导,即两式可逆:
\[
\begin{cases}
f(k)=\sum_{i=0}^k \alpha_{i,k} g(i)
\\g(k)=\sum_{i=0}^k \beta_{i,k} f(i)
\end{cases}
\tag{S}
\]
也就是说,只要选取了适当的系数\(\alpha_{i,j}\)和\(\beta_{i,j}\),就可以进行反演。
这里张贴几个比较常见的反演公式:
二项式反演:
\[
\begin{cases}
a_n=\sum_{k=0}^n \dbinom{n}{k} b_k
\\b_n=\sum_{k=0}^n (-1)^{n-k}\dbinom{n}{k}a_k
\end{cases}
\tag{1}
\]
\[
\begin{cases}
a_n=\sum_{k=n}^\infty \dbinom{n}{k} b_k
\\b_n=\sum_{k=n}^\infty (-1)^{n-k}\dbinom{n}{k} a_k
\end{cases}
\tag{2}
\]
\[
\begin{cases}
a_n=\sum_{k=0}^n \dbinom{n+p}{k+p} b_k
\\b_n=\sum_{k=0}^n (-1)^{n-k}\dbinom{n+p}{k+p} a_k
\end{cases}
\tag{3}
\]
\[
\begin{cases}
a_n=\sum_{k=n}^\infty \dbinom{n+p}{k+p} b_k
\\b_n=\sum_{k=n}^\infty (-1)^{n-k}\dbinom{n+p}{k+p} a_k
\end{cases}
\tag{4}
\]
斯特林数反演:
\[
\begin{cases}
a_n=\sum_{k=0}^n s(n,k) b_k
\\ b_n=\sum_{k=0}^n S(n,k) a_k
\end{cases}
\tag{5}
\]
这里的公式又叫序列反演,其本质上和函数的反演是差不多的。
这里只张贴\((1)\)式的证明,其他的不多赘述。
Mobius 反演
有没有一种反演可以适用于更加通用的情况,而不必求所谓的系数呢?我们可以考虑莫比乌斯变换。
莫比乌斯反演适用于偏序关系的运算。莫比乌斯反演依赖于所谓的“偏序集”。如果一个非空集合\(X\)上存在一个关系 “\(\preceq\)”,满足三个性质:
- 自反。\(\forall a \in X , a \preceq a\)
- 反对称。如果对于两个不同元素\(a ,b\) 有$ a \preceq b$ ,就一定不满足 \(b \preceq a\)。
- 传递。如果对于三个不同元素\(a,b,c\),\(a\preceq b,b \preceq c\),则一定有\(a \preceq c\)。
我们就把\(X\)和这个关系\(\preceq\) 一起叫做一个偏序集,记为\(<X,\preceq>\)。
注意,如果偏序集\(<X,\preceq>\)中,任意两个元素\(a,b\)一定满足\(a\preceq b\)或\(b \preceq a\),就把这个偏序集称为全序集,把\(\preceq\)称为全序关系。
我们高一接触过的“包含于”\(\subseteq\)就是一个典型的偏序关系,但它不是全序关系。不少老师曾经用\(\leq\)来类比\(\subseteq\),是有一定的道理的。常见的,\(<\mathbb{N},\leq>\)是一个全序集。
更近一步地,我们考虑所谓的局部有限偏序集。对于任何元素\(x,y \in X\),都只有有限个\(a\) 满足 \(x \preceq a \preceq y\),就称\(<X.\preceq>\)是局部有限偏序集。终于,我们可以此用莫比乌斯反演了。在\(X\)上定义函数:
\[
\mu(x,y)=
\begin{cases}
1 & x=y
\\ -\sum\limits_{x \preceq u \prec y} \mu(x,u) & x\prec y
\\ 0 & else
\end{cases}
\]
我们有莫比乌斯反演定理:
设\(f(x)\),\(g(x)\)是\(X\)上的整数函数,则以下两式可逆:
\[
\begin{aligned}
& f(x)=\sum_{0 \preceq u \preceq x} g(u)
\\ & g(x)=\sum_{0 \preceq u \preceq x} \mu(u,x) f(u)
\end{aligned}
\]
其中\(0\)是\(X\)上的最小元。
在比赛中,最为常用的就是定义在\(<\mathbb{Z}^{+},|>\)的莫比乌斯反演了。我们重点讲解这个。
按照定义,这个莫比乌斯反演写成:
\[
\begin{aligned}
& f(x)=\sum_{1 | d || x} g(d)
\\ & g(x)=\sum_{1 | d || x} \mu(d,x) f(d)
\end{aligned}
\]
其中\(x || y\)表示\(x|y\)且\(x \neq y\)。
定义莫比乌斯函数:
\[
\mu(x,y)=
\begin{cases}
1 & x=y
\\ -\sum\limits_{x | u || y} \mu(x,u) & x||y
\\ 0 & else
\end{cases}
\]
固定其中的\(x = 1\),通过复杂的演算,我们得到:
\[
\mu(n) = \begin{cases}
1 & n = 1\\
(-1)^k & n = p_1p_2\cdots p_k,\text{且}p_1,p_2,\cdots,p_k\text{为互不想等的素数}\\
0 & \text{else}
\end{cases}
\]
最后反演的表达式:
\[
\begin{aligned}
& f(x)=\sum_{d | x} g(d)
\\ & g(x)=\sum_{d | x} \mu(\frac{x}{d}) f(d)
\end{aligned}
\]
当然,这样得到反演的表达式未免过于复杂。网上有很多利用Dirichlet卷积证明莫比乌斯反演的博客。那里的证明相对来说会更加简洁易懂。
我们再试一下其他的偏序集:对幂集(子集)的偏序集\(<P(S),\subseteq>\)上的Mobius反演:
定义:
\[
\mu(B,A) =
\begin{cases}
(-1)^{|A|-|B|} & B \subseteq A
\\ 0 & else
\end{cases}
\]
则以下两式可逆:
\[
\begin{aligned}
& f(A)=\sum_{H \subseteq A} g(H)
\\ & g(B)=\sum_{H \subseteq B} (-1)^{|B|-|H|}f(H)
\end{aligned}
\]
这个反演又叫作“子集反演”。如果你想具体应用这个反演,不妨尝试做一下这道题:SNOI2017 遗失的答案
不过在现在,这样的莫比乌斯反演过于晦涩和难懂。在目前的算法界乃至学术界,公认的莫比乌斯反演都是基于\(\langle \mathbb{Z}^{+}, |\rangle\)上的。不同的反演,已经被赋予了新的名字;而在讲到反演的原理时,人们更多会提到容斥原理。
然而这里的莫比乌斯反演更好的揭示了这一系列算法的本质:给定一个偏序集上的前缀和,通过差分变换,求出每个偏序集元素的权值。正因如此,莫比乌斯反演才在沟通容斥原理和其他数学分支上展现了重要的地位。
题外话:子集的枚举
提到“子集反演”,我们不妨想到一个问题:如何用循环语句求\(\sum_{A \subseteq U}f(A)\)?
不难想到,当\(|A|\)比较小的时候,我们可以状态压缩,用一个\(|A|\)位二进制数来表示,每一位都是这个集合的特征函数。
对我来说,枚举子集的第一思路是枚举每一位非\(0\)位,依次尝试将它们修改为\(0\)。这样听起来很科学,但是不好实现。
前几天,我看到了这样一种枚举方式:
for(rg ll subset = U; subset; subset = (subset - 1) & U) { /* do something with the subset */ }
当每次subset-1
时,当前最近的为\(1\)的部分会被删去,而剩余部分会被补上\(1\)。通过&U
的操作,可以把不属于\(U\)的元素删去。与运算是不增的,因此枚举的子集一定会越来越小。
来源:https://www.cnblogs.com/LinearODE/p/10719164.html