FMT 和 子集卷积

FMT 和 子集卷积

FMT

给定数列 $ a_{0\dots 2^{k}-1} $ 求 $ b $ 满足 $ b_{s} = \sum_{i\in s} a_i $

实现方法很简单,

for( i in 0..n-1 ) 
    for( j in 0..2^n-1)
        if( j & ( 1 << i ) ) 
            a[j] += a[j ^ ( 1 << i )]

然后称为 $ B = FMT(A) $ ,快速莫比乌斯变换

想要还原也很简单,把代码反着写:

for( i in n-1 downTo 0 ) 
    for( j in 2^n - 1 downTo 0)
        if( j & ( 1 << i ) ) 
            a[j] -= a[j ^ ( 1 << i )]

当然, $ i $ 的顺序可以是原来的顺序,因为按照哪个顺序枚举位根本不重要

同时,$ j $ 的顺序也不重要,考虑对于一个数字,它只有在当前枚举的位数为 1 的时候才被执行,所以就算已经枚举到这位是 0 的状态,它也不会被更新。

这样 $ A = IFMT( B ) $

FMT 可以写成 FFT 那样的形式,就不赘述了。

或卷积

或卷积就需要用到这个东西。

或卷积是指:
\[ C_x = \sum_{i|j=x} A_i B_j \]
有一个结论, $ FMT(C) = FMT(A) + FMT(B) $

原因是 $ (i | j) = s $ 等价于 $ (i \sube s) and (j \sube s) $

所以有 $ C = IFMT( FMT(A) + FMT(B) ) $

于是可以 $ O(n2^n) $ 做这个。

子集卷积

子集卷积张这样:
\[ C_s = \sum_{i|j=s,i\&j = 0} A_i B_j \]

如果设 $ p(x) $ 为 $ x $ 的 popcount ,那么:
\[ (i|j = s) , (i\&j = 0) \Leftrightarrow i|j = s , p(i)+p(j) = p(s)\\C_s = \sum_{i|j = s , p(i)+p(j) = p(s)} A_iB_j \]
我们把 $ c $ 扩展到二维,设 $ c'{p,k} $,定义如下:
\[ c'_{p,s} = \sum_{i|j = s,p(i)+p(j) = p} a_ib_j[p(s) = p] \]
把 $ c $ 扩展到二维了,$ a $ 也需要扩展到二维,所以定义 $ a'
{p,s} $
\[ a'_{p,s} = \left\{\begin{aligned}&0 & {p(s) \neq p}\\&a_{s} & {p(s) = p} \end{aligned}\right. \]
同理定义 $ b'_{p,s} $

我们知道
\[ c'_{p,s} = \sum_{i|j = s,p(i)+p(j) = p} a'_{p(i),i} b'_{p(j),j} \]
观察到 $ c'p = \sum{i=0}^p a'{i}\times{or} b'_{p-i} $ ,而且需要去掉左边的 $ p(s) \neq p $ 的情况。

这样复杂度 $ O(n^3 2^n) $,一共要卷 $ n^2 $ 次。

注意 $ FMT , IFMT $ 都有可加性,所以我们把那个或卷积写成 $ FMT $ 的形式
\[ \begin{aligned}c'_{p} &= \sum_i IFMT(FMT(a'_i) · FMT(b'_{p-i}))\\&= IFMT( \sum_i FMT(a_i') · FMT(b_{p-i}') )\end{aligned} \]
我们现在只需要处理出所有 $ a'_i $ 和 $ b'_i $ 的卷积,最后再跑 $ n $ 次逆 FMT ,所以这样做就优化到了 $ O( 2^n n^2 ) $

上一篇:线性回归


下一篇:DeepFaceLab20191220新功能:大幅提升图片质量!