码迷,mamicode.com
首页 > 其他好文 > 详细

FWT

时间:2019-06-16 13:52:21      阅读:106      评论:0      收藏:0      [点我收藏+]

标签:spl   math   time   href   简单   两种   set   根据   前缀和   

\(FFT\)(快速傅里叶变换)求的是卷积,也就是
\[ C_k=\sum_{i+j=k}A_iB_j \]
那么\(FWT\)(快速沃尔什变换)求的就是子集卷积,也就是
\[ C_{k}=\sum_{i \oplus j=k} A_{i} B_{j} \]
\(\oplus\)指按位运算\(or,and,xor\)

其实\(or,and\)卷积应该是\(FMT\)(快速莫比乌斯变换),因为思想较为类似,故写在一篇博客中。

\(FMT\)

先介绍\(or\)卷积,因为感性上理解\(or\)\(and\)操作较为类似,所以两者实际是等价的。

根据\(FFT\)的思路,我们同样需要变换出一个函数使得
\[ FMT(A)_i\times FMT(B)_i=FMT(C)_i \]
然后莫比乌斯变换就是构造了下面这个式子:
\[ FMT(A)_n=\sum _{i \subseteq n}A_i \]
证明也很简单:
\[ \sum_{i \subseteq n} A_{i} \sum_{j \subseteq n} B_{j}=\sum_{i, j \subseteq n} A_{i} B_{j}=\sum_{k \subseteq n} \sum_{i | j=k} A_{i} B_{j} \]
注意到
\[ C_k=\sum_{i\oplus j = k}A_iB_j \]
那么
\[ FMT(A)_n\times FMT(b)_n=\sum_{k\subseteq n}=FMT(C)_n \]
于是我们需要快速地求出子集和。

有两种主要的方法,一种是高维前缀和,可以看这里

另一种是分治的算法,借一张网上的图,箭头表示累加,应该就能理解了。

技术图片

变回去是把累加改为减就可以了。

代码如下:

void FMT(int *a, int n, int x)
{
    for (int i = 1; i <= 1 << n; i <<= 1)
        for (int j = 0; j < 1 << n; j += (i << 1))
            for (int k = 0; k < i; ++k)
                a[i + j + k] += a[j + k] * x;
}

\(and\)卷积也很类似
\[ FMT(A)_n=\sum_{n\subseteq i}A_i \]
代码如下:

void FMT(int *a, int n, int x)
{
    for (int i = 1; i <= 1 << n; i <<= 1)
        for (int j = 0; j < 1 << n; j += (i << 1))
            for (int k = 0; k < i; ++k)
                a[j + k] += a[i + j + k] * x;
}

\(FWT\)

未完待续。。。

参考文献:《真正理解快速沃尔什变换/快速莫比乌斯变换(FWT|FMT)》

FWT

标签:spl   math   time   href   简单   两种   set   根据   前缀和   

原文地址:https://www.cnblogs.com/ACMSN/p/11031072.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!