高维前缀和 & FMT

高维前缀和 & FMT

例题 ( ARC136D ):

\(n\) 个小于 \(10^6\) 的数 \(a[1\cdots n]\),求有多少对数相加后不仅进位。

做法

考虑两数相加不进位,等价于两数拆分成十进制后每个相同位上的数之和不超过 \(9\)

那么我们考虑枚举一个数,计算有多少个数,对十进制每一位,都满足小于某数码的限制。

这个问题就可以用高维前缀和解决。

具体来说,我们设 \(F(S)=\sum\limits_{S'}a_{S'}\),其中 \(S'\) 满足每一位都严格小于等于 \(S\) 的对应位,

在二进制下就是 \(F(S)=\sum\limits_{S'\subseteq S}a_{S'}\),高进制的也可以用高维数组的形式更清晰的写出来。

那么我们考虑如何快速计算 \(F(S)\) 的值,这时我们可以采用递推的方法,即:

\(f(i,S)=\sum\limits_{S'}a_{S'}\),满足 \(S'[0,i-1]\subseteq S[0,i-1],S'[i,n-1]=S[i,n-1]\)

注意,因为高进制的方法不难从二进制下拓展,故为了方便书写,我们只讨论二进制下的情况。

我们考虑推出 \(f(i+1,S)\),发现其与 \(f(i,S)\) 唯一的变化是 \(S'\)\(i\) 位可以取的值域,

那么我们就有:

初始时:\(f(-1,S)=a_S\)

递推时:

  1. \(f(i+1,S)=f(i,S)\)\(S[i]=0\)
  2. \(f(i+1,S)=f(i,S)+f(i,S\verb|\| \verb|{i}|)\)\(S[i]=1\).

而最后的 \(F(S)\) 就等于 \(f(n,S)\)

这种递推的方法,显然在任意进制下都有很好的应用空间,

而应用在高进制下的这种方法,实际上就是一种维护高维前缀和的有力手段。

实际上,上述算法的过程还是是可逆的,就是说我们可以通过一些手段从 \(F\) 快速倒推回 \(a\)

这里我们考虑高维前缀和的另一个递推式,即利用了容斥思想写出的递推式:

\(F(S)=a_{S}+\sum\limits_{S'\subset S}(-1)^{|S|-|S'|+1}F(S')\)

即考虑与 \(S\) 全相等的,有一位不同的,有两位不同的,\(\cdots\) 并将这些类的贡献分别乘上系数后求和。

我们考虑将式子做一些转化,并用 \(F\) 去表示 \(a\),即:

\(a_{S}=F(S)-\sum\limits_{S'\subset S}(-1)^{|S|-|S'|+1}F(S')\)

\(= F(S)+\sum\limits_{S'\subset S}(-1)^{|S|-|S'|}F(S')\)

\(= \sum\limits_{S'\subseteq S}(-1)^{|S|-|S'|}F(S')\).

注意到,此时的逆表达式竟然和原来的正表达式非常相像,唯一相差的就是一个 \(-1\) 幂次的系数。

那么,我们依葫芦画瓢,和正表达式的快速计算类似,我们仍然用递推的方法解决问题。

那么,这时我们设 \(A(i,S)=\sum\limits_{S'}F_{S'}\),满足 \(S'[0,i-1]\in S[0,i-1],S'[i,n-1]=S[i,n-1]\)

类似的,我们考虑表示 \(A(i+1,S)\)\(A(i,S)\) 间的变化量来递推,只需要注意乘上系数,即:

初始时:\(A(-1,S)=F(S)\)

递推时:

  1. \(A(i+1,S)=A(i,S)\)\(S[i]=0\)
  2. \(A(i+1,S)=A(i,S)-A(i,S\verb|\| i)\)\(S[i]=1\).

那么这就是逆推的方法。

这个逆推和正推结合在一起,就是我们所说的快速莫比乌斯变换,即 FMT

它的一个应用场景是计算集合并卷积以及集合交卷积,即以下题目:

我们有两个序列 \(A,B\),需要求序列 \(C_i=\sum\limits_{j|k=i}A_jB_k\)

我们考虑用 FMT 来快速解决上述问题,大体思路和 FFT 类似,

只不过把点值与系数间的变换,变成了原序列与子集和序列的变换。

具体来说,对于任意序列 \(X\),我们记 \(X'_i=\sum\limits_{j\in i}X_j\),则我们有:

\(C'_i=\sum\limits_{j|k\subseteq i}A_jB_k=\sum\limits_{j\subseteq i, k\subseteq i}A_jB_k=(\sum\limits_{j\subseteq i}A_j)(\sum\limits_{k\subseteq i}B_k)=A'_iB'_i\)

这个式子意味着,我们只要快速计算出 \(A'\)\(B'\),就能快速计算出 \(C'\),再逆推回去就得到了 \(C\)

以上就是集合并卷积的做法,而集合交卷积可以通过容斥的思想来完全转化成集合并卷积。

文章至此也就结束了,至于时间复杂度,显然是 \(O(n2^n)\) 的,其中 \(n\) 是需要变换的序列的长度取对数。

posted @ 2022-02-28 23:36  GaryH  阅读(81)  评论(0编辑  收藏  举报