FMT 和 FWT 入门

· · 算法·理论

【预备知识】

子集反演公式:

f(S)=\sum_{T\subseteq S}g(T)\iff g(S)=\sum_{T\subseteq S}(-1)^{|S|-|T|}f(T) f(S)=\sum_{S\subseteq T}g(T)\iff g(S)=\sum_{S\subseteq T}(-1)^{|S|-|T|}f(T)

如果用 g 直接暴力算 f,复杂度是 O(3^n) 的;使用 SOSDP 则可以把复杂度优化至 O(n\cdot 2^n),具体不再赘述。

f 子集反演算 g 也可以 SOSDP,同样 O(n\cdot 2^n) 求)

【FMT】

FMT,快速莫比乌斯变换。它解决这么一个问题:

给定两个序列 a_0\sim a_{2^n-1}b_0\sim b_{2^n-1},求序列 c_0\sim c_{2^n-1},满足:将下标 I 看作 n 大小的子集,c_I=\sum_{J\cup K=I}a_J\cdot b_K

这种问题叫或卷积。

N=2^n,首先容易发现有一个 O(N^2) 的解法,即枚举 J,K 累加答案。

FMT 可以用来解决这类问题,复杂度为 O(N\log N)=O(2^n\cdot n),和 SOSDP 一样。

下面介绍一下 FMT。

在开始之前,我们先回顾一下 FFT 是怎么做普通卷积的。

  1. a,b 分别做 DFT。

  2. 求出 c 的 DFT。

  3. 做 iDFT 求出 c

这个做法的关键在于:存在一个变换 DFT,使得 DFT 和 iDFT 做起来都很快,而且 \mathrm{DFT}(a*b)=\mathrm{DFT}(a)\cdot \mathrm{DFT}(b)

然后回到原问题。我们记 a\oplus ba,b 的或卷积。

为了解决问题,我们希望找到变换 t 满足:t 和 it 都很快,且 \mathrm{t}(a\oplus b)=\mathrm{t}(a)\cdot \mathrm{t}(b)

一个很牛的事实是,这种变换确实存在,它们叫做 DMT 和 iDMT。即莫比乌斯变换和逆莫比乌斯变换。

介绍一下,\mathrm{DMT}(a)=(\overline{a_0},\dots,\overline{a_N}),其中 \overline{a_I}=\sum_{J\subseteq I}a_J。即把 a 变换为它的前缀和。显然做这个变换和逆变换可用 SOSDP 在 O(n\cdot 2^n) 做,问题只剩下一个性质。

引理:c=a\oplus b,则 \overline{c}=\overline{a}\cdot\overline{b}

证明:

\begin{aligned} \overline{c_X}&=\sum_{I\subseteq X}c_I\\ &=\sum_{I\subseteq X}\sum_{J\cup K=I}a_J\cdot b_K\\ &=\sum_{J\subseteq X}\sum_{K\subseteq X}a_J\cdot b_K\\ &=(\sum_{J\subseteq X}a_J)\cdot (\sum_{K\subseteq X}b_K)\\ &=\overline{a_X}\cdot \overline{b_X} \end{aligned}

因此可以 O(n\cdot 2^n)a,b 的高维前缀和,乘起来之后再用子集反演 O(n\cdot 2^n) 求出 c

另外,FMT 还可以做与卷积:把 \overline{a_I}=\sum_{J\subseteq I}a_J 换做 \overline{a_I}=\sum_{I\subseteq J}a_J 即可。证明过程也类似,方向换一下即可。

【FWT】

FWT,快速沃尔什变换,用于解决异或卷积问题。问题定义类似。

同样地,我们要找一个变换 t,同样满足上面的性质。

而一样很牛的事实是,这样的变换也存在,叫做 DWT 和 iDWT。

看起来相当奇怪。 先说明 DWT 和 iDWT 都可以 $O(n\cdot 2^n)$ 计算。 **引理**:$\mathrm{iDWT}(a)=\mathrm{DWT}(a)/2^n$。 **引理证明**: 转证 $\mathrm{DWT}(\mathrm{DWT}(a))=a\cdot 2^n$,这和引理是等价的。 为什么呢? 令 $b=\mathrm{DWT}(a)$,由原本引理有 $\mathrm{DWT}(b)=a\cdot 2^n\iff\mathrm{DWT}(b)/2^n=a\iff \mathrm{DWT}(b/2^n)=a\iff b/2^n=\mathrm{iDWT}(a)$,能这么做的原因是 DWT 其实是**线性变换**,所以 $\mathrm{DWT}(x)/C=\mathrm{DWT}(x/C)$。 接下来证明转化命题。不妨设 $b=\mathrm{DWT}(a),c=\mathrm{DWT}(b)$,求证 $c_I=a_I\cdot 2^n$。 $$ \begin{aligned} c_I&=\sum_{J}(-1)^{|I\cap J|}b_J=\sum_{J}(-1)^{|I\cap J|}\sum_{K}(-1)^{|J\cap K|}a_K\\ &=\sum_{K}a_K\sum_{J}(-1)^{|I\cap J|}(-1)^{|J\cap K|}\\ &=\sum_{K}a_K\sum_{J}(-1)^{|I\cap J|\oplus|J\cap K|}\\ &=\sum_{K}a_K\sum_{J}(-1)^{|(I\oplus K)\cap J|}\\ \end{aligned} $$ 观察上式,$(I\oplus K)\cap J$ 有什么规律?当 $I\oplus K=\empty$ 时,$J$ 无论怎么取,系数都是 $1$,因此 $\sum_J(-1)^{\cdots}=2^n$;而 $I\oplus K\neq \empty$ 时,系数会正负抵消,总共的贡献为 $0$。 因此,$\sum_{J}(-1)^{|(I\oplus K)\cap J|}=2^n$,得证。 ------------- **算法**:只考虑怎么 DWT。 设 $f$ 为 $a$ 的前 $2^{n-1}$ 项的 $2^{n-2}\sim 2^0$ 位的结果,$g$ 为后 $2^{n-1}$ 项的 $2^{n-2}\sim 2^0$ 位的结果。**注意是只考虑更低位。** 有结论:$\mathrm{DWT}(a)=(\mathrm{DWT}(f)+\mathrm{DWT}(g),\mathrm{DWT}(f)-\mathrm{DWT}(g))$,即前一半项是求和,后一半项是做差。 如果有这个结论,很显然就可以分治 $O(N\log N)=O(n\cdot 2^n)$ 来做。其实这和 FFT 非常相似,区别只在于 DFT 是按照奇偶分治下去,DWT 直接按下标分治。 问题只在于结论证明。 ------------------ **求证**:$\forall 0\le I< 2^{n-1}$,$\hat{a_I}=\hat{f_I}+\hat{g_I}$,$\hat{a}_{I+2^{n-1}}=\hat{f}_I-\hat{g}_I$。 **证明**: $$ \begin{aligned} \hat{a}_I(I<2^{n-1})&=\sum_{0\le J<2^n}(-1)^{|I\cap J|}a_J\\ &=\sum_{0\le J<2^{n-1}}(-1)^{|I\cap J|}a_J +\sum_{2^{n-1}\le J<2^n}(-1)^{|I\cap J|}a_J\\ &=\hat{f}_I+\sum_{2^{n-1}\le J<2^n}(-1)^{|I\cap J|}a_J\\ &=\hat{f}_I+\sum_{0\le J'<2^{n-1}}(-1)^{|I\cap (J'+2^{n-1})|}a_{J'+2^{n-1}}\\ &=\hat{f}_I+\sum_{0\le J<2^{n-1}}(-1)^{|I\cap (J+2^{n-1})|}a_{J+2^{n-1}}\\ &=\hat{f}_I+\sum_{0\le J<2^{n-1}}(-1)^{|I\cap J|}a_{J+2^{n-1}} \text{ (注意 I 的范围)}\\ &=\hat{f}_I+\hat{g}_I\\ \end{aligned} $$ $$ \begin{aligned} \hat{a}_{I+2^{n-1}}(I<2^{n-1})&=\sum_{0\le J<2^n}(-1)^{|(I+2^{n-1})\cap J|}a_J\\ &=\sum_{0\le J<2^{n-1}}(-1)^{|(I+2^{n-1})\cap J|}a_J +\sum_{2^{n-1}\le J<2^n}(-1)^{|(I+2^{n-1})\cap J|}a_J\\ &=\sum_{0\le J<2^{n-1}}(-1)^{|I\cap J|}a_J +\sum_{0\le J<2^{n-1}}(-1)^{|(I+2^{n-1})\cap (J+2^{n-1})|}a_J\\ &=\hat{f}_I+\sum_{0\le J<2^{n-1}}(-1)^{|I\cap J|+1}a_J\\ &=\hat{f}_I-\hat{g}_I\\ \end{aligned} $$ 证毕。 ----------- 然后说明 $\mathrm{DWT}(a\oplus b)=\mathrm{DWT}(a)\cdot \mathrm{DWT}(b)$。 证明: **引理**:$(-1)^{|I\oplus J|}=(-1)^{|I|}\cdot (-1)^{|J|}$。 比较显然,因为异或后受到影响的只有同时在 $I,J$ 中的元素,左边会让它们的影响变成 $1$,而右边在 $I,J$ 中各算一个 $-1$,乘起来还是 $1$。 **证明**: $$ \begin{aligned} \hat{c_X}&=\sum_{I}(-1)^{|I\cap X|}\sum_{J\oplus K=I}a_J\cdot b_K\\ &=\sum_{J,K}(-1)^{|X\cap(J\oplus K)|}a_Jb_K\\ &=\sum_{J,K}(-1)^{|(J\cap X)\oplus(K\cap X)|}a_Jb_K\\ &=\sum_{J,K}(-1)^{|J\cap X|}a_J\cdot (-1)^{|K\cap X|}b_K\\ &=\sum_{J}(-1)^{|J\cap X|}a_J\cdot \sum_{K}(-1)^{|K\cap X|}b_K\\ &=\hat{a_X}\cdot \hat{b_X} \end{aligned} $$ # 【深入理解】 可能会觉得 DMT, DWT 的式子比较生硬,于是我们深入理解一下这两个东西到底在干嘛。 **DFT 是在做点值,DMT 和 DWT 其实也是在做另一种意义上的点值。** 具体来说,我们需要用到**集合幂级数**。 对于一个序列 $a_0\sim a_N$,定义一个多元多项式 $A(x_1\sim x_n)=\sum_{0\le I<2^{n}}a_I\cdot x_1^{i_1}x_2^{i_2}\cdots x_n^{i_n}$,其中 $i_1\sim i_n$ 是 $I$ 这个集合的二进制表示。 这个多项式有 $2^n$ 项,每一项的系数就是 $a$。这个 $A$ 叫做**集合幂级数**。可以类比序列对应到 OGF 上。简记 $A(x_1\sim x_n)=\sum_{0\le I<2^{n}}a_I\cdot x_1^{i_1}x_2^{i_2}\cdots x_n^{i_n}$ 为 $A(x)=\sum_{I}a_Ix^I$。 --- 看看 DMT 是在干嘛。令 $J=(j_1,\dots,j_n)\in \{0,1\}^n$,即一个集合。 注意到当 $I\not\subseteq J$,存在 $i_t=1,j_t=0$,此时有 $j_t^{i_t}=0$,所以 $j_1^{i_1}\cdots j_n^{i_n}=0$。 而 $I\subseteq J$ 时,$(i_t,j_t)=(0,0)/(0,1)/(1,1)$,$j_t^{i_t}=1$,所以 $j_1^{i_1}\cdots j_n^{i_n}=1$。 因此,$A(J)=\sum_{I\subseteq J}a_I=\overline{a}_J$。 所以 DMT 计算 $\overline{a}$ 实际上是求出了 $A$ 在 $\{0,1\}^n$ 这 $2^n$ 个点处的值。 ---- 再看看 DWT 是在干嘛。令 $J=(j_1,\dots,j_n)\in \{0,1\}^n$,即一个集合。 那么 $P=((-1)^{j_1},(-1)^{j_2},\dots,(-1)^{j_n})\in \{-1,1\}^n$。 $$ \begin{aligned} A(P)&=\sum_{0\le I< 2^n}a_I(-1)^{i_1j_1}(-1)^{i_2j_2}\cdots (-1)^{i_nj_n}\\ &=\sum_{0\le I<2^n}a_I(-1)^{i_1j_1+\cdots+i_nj_n}\\ &=\sum_{0\le I<2^n}a_I(-1)^{I\cdot J} \end{aligned} $$ **注**:向量 $a,b$ 的点乘 $a\cdot b=\sum a_ib_i$。上面 $i\cdot j$ 实际上是把 $i,j$ 两个集合看作了向量(或者说 01 串)进行运算。 而 $i\cdot j$ 在某一位上取 $1$,当且仅当这一位上 $i,j$ 都是 $1$,所以: $$ \begin{aligned} A(P)=\sum_{0\le I<2^n}a_I\cdot (-1)^{|I\cap J|}=\hat{a}_J \end{aligned} $$ 所以 DWT 实际上是求出了 $A$ 在 $\{-1,1\}^n$ 这 $2^n$ 个点处的值。 总之,FFT, FMT, FWT 都是在先点值后插值。 ![](C:\Users\fly_l\AppData\Roaming\marktext\images\2024-12-18-21-14-01-image.png) # 例题 经验:**什么涉及位运算,什么就作为集合幂级数的指数。** 例如要求一些东西的与等于 $p$,放到集合幂级数的指数上,定位乘法为与卷积后,答案就是 $x^p$ 的系数。 ## Nim (Topcoder 11469) 问有多少序列 $(i_1\sim i_m)$ 满足: 1. $i_1\oplus\cdots\oplus i_m=0$。 2. $1\le i_j\le k$。 3. $i_j$ 为质数。 $m\le 10^9,k\le 50000$。 --- 构造一个序列 $a_0\sim a_{65536}$,使 $a_I=1\iff 1\le I\le K,I\in Prime$。 构造一个集合幂级数 $A(x)=\sum a_Ix^I$。 在乘法定义为异或卷积($a_Ix^I\cdot b_Jx^J=a_Ib_Jx^{I\oplus J}$)时,$A^m(x)$ 中 $x^0$ 的系数就是答案。 那 $A^m(x)$ 怎么算? $$ \begin{aligned} A^{(m)}(x)&=\mathrm{iDWT}(\mathrm{DMT}(A^{(m)}(x))\\ &=\mathrm{iDMT}((\mathrm{DMT}(A(x))^m)\\ \end{aligned} $$ 因此只要做一次 $\mathrm{DMT}$,然后让所得序列的每一项变成 $m$ 次方,再做一次 $\mathrm{iDMT}$ 即可。注意这里是点乘 $m$ 次不是卷积 $m$ 次。 这题可以类比多项式快速幂:$f^m(x)=\exp \ln f^m(x)=\exp m\ln f(x)$。 ## CF449D 给定 $a_1\sim a_n$,计数 $(1\le i_1<\cdots<i_k\le n)$,使 $a_{i_1}\,\mathrm{and}\,a_{i_2}\,\mathrm{and}\cdots\mathrm{and}\,a_{i_k}=0$。 $n,a_i\le 10^6$。 --- 考虑取 $u=2^{20}-1$。定义集合幂级数 $F(x)=\prod(x^{a_i}+x^u)$。这里 $x^{a_i}$ 和 $x^u$ 都是集合幂级数,$u$ 相当于全集。也就是说,令 $A(x)=\sum_{I}[I=a_i]x^I,U(x)=\sum_{U}[I=U]x^I$,则 $x^{a_i}+x^u=A(x)+U(x)$。 令乘法为与卷积,答案就是 $F(x)$ 中 $x^0$ 的系数。这也说明为什么取 $u=2^{20}-1$,因为全集是与运算的单位元。 问题转化为求 $[x^0]F(x)$。令 $\mathrm{DMT'}$ 为与卷积的点值。 $F(x)=\mathrm{iDMT'}(\mathrm{DMT'}(x^{a_1}+x^u)\cdots \mathrm{DMT'}(x^{a_n}+x^u))$。注意在做了 $\mathrm{DMT'}$ 后的乘法是点乘。 注意到 $x^{a_i}+x^u$ 每一项的系数只有在 $a_i,u$ 处才取 $1$,其余为 $0$。 所以做 $\mathrm{DMT'}$ 后,每一项系数为 $1/2$。当 $I\subseteq a_i$ 时为 $2$,其余为 $1$。($\check{a}_I=\sum_{I\subseteq J}a_J$) 这有什么用呢?记 $\check{S}_I=(\prod (x^{a_i}+x^u))_I$,有 $\check{S}_I=2^{t_I}$,其中 $t_I$ 表示 $a_1\sim a_n$ 中包含 $I$ 的个数。 那么问题转化为求 $t_0\sim t_{2^n-1}$,即给定一些集合,求每个集合被多少个包含。这也是 SOSDP 能做的。如果要类比 $\mathrm{DMT'}$,令 $cnt(J)$ 为 $a_1\sim a_n$ 中 $J$ 的个数。则 $t_I=\sum_{I\subseteq J}cnt(J)$,也是后缀和。 那么这一题就做完了,复杂度 $O(20\cdot 2^{20})$ 求 $t_0\sim t_{2^n-1}$,然后 $O(20\cdot 2^{20})$ 做一次 $\mathrm{iDMT'}$ 得到 $F(x)$,答案取 $x^0$ 系数。