快速沃尔什变换(FWT)

快速沃尔什变换(FWT)

前言

本文为个人学习笔记,大量参考了 oi-wiki 以及其他博客的内容。

问题

给定 a,b 序列,求:

ci=i=jkajbk

其中,=or/and/xor

做法

核心思想

对于某种特定的 ,找到序列 FWTa,FWTb,FWTc 分别对应序列 a,b,c,需要满足以下性质和要求:

1、FWTci=FWTaiFWTbi

2、需要在优秀的时间复杂度内进行 aFWTa 的变换。

下面一个一个符号来。

or

FWTai=j,j|i=iajFWTaiFWTbi=j,j|i=iajk,k|i=ibj=j,k,(j|k)|i=i(ajbk)=FWTci

考虑 aFWTa 的变换,考虑分治处理,写出如下形式(a0,a1,a2,a3,a4,a5,a6,a7):

轮数 长度 FWT0 FWT1 FWT2 FWT3 FWT4 FWT5 FWT6 FWT7
1 1 a0 a1 a2 a3 a4 a5 a6 a7
2 2 a0 a0+a1 a2 a2+a3 a4 a4+a5 a6 a6+a7
3 4 a0 a0+a1 a0+a2 a0+a1+a2+a3 a4 a4+a5 a4+a6 a4+a5+a6+a7
4 8 a0 a0+a1 a0+a2 a0+a1+a2+a3 a0+a4 a0+a1+a4+a5 a0+a2+a4+a6 a0+a1+a2+a3+a4+a5+a6+a7

容易写出以下代码,

inline void FWT_OR(int *A) {
    for (int len = 2; len <= (1 << n); len *= 2)
        for (int x = 0; x < (1 << n); x += len)
            for (int i = x; i < x + len / 2; ++ i)
                A[i + len / 2] = (A[i] + A[i + len / 2]) % mod;
}

对于 FWTa 变换为 a,反着把 FWTa 数组转化为 a 数组即可。

inline void IFWT_OR(int *A) {
    for (int len = (1 << n); len >= 2; len /= 2)
        for (int x = 0; x < (1 << n); x += len)
            for (int i = x; i < x + len / 2; ++ i)
                A[i + len / 2] = (A[i + len / 2] - A[i]) % mod;
}

and

FWTai=j,j&i=iajFWTaiFWTbi=j,j&i=iajk,k&i=ibj=j,k,(j&k)&i=i(ajbk)=FWTci

FWTaa 的变换同上。

inline void FWT_AND(int *A) {
    for (int len = 2; len <= (1 << n); len *= 2)
        for (int x = 0; x < (1 << n); x += len)
            for (int i = x; i < x + len / 2; ++ i)
                A[i] = (A[i] + A[i + len / 2]) % mod;
}

inline void IFWT_AND(int *A) {
    for (int len = (1 << n); len >= 2; len /= 2)
        for (int x = 0; x < (1 << n); x += len)
            for (int i = x; i < x + len / 2; ++ i)
                A[i] = (A[i] - A[i + len / 2]) % mod;
}

xor

这个比较难。

以下摘自 oi-wiki。

若我们令 xy 表示 xy 中 1 数量的奇偶性,即 xy=popcnt(xy)mod2,那么容易有 (xy)xor(xz)=x(yxorz)

下证上式((xy)xor(xz)=x(yxorz)):

只考虑 x 的二进制中为 1 的位,xy 中 1 的数量 和 xz 中 1 的数量可以分成三个部分:

1、都有的数量 A

2、仅有 y 有的数量 B

3、仅有 z 有的数量 C

即证明:((A+B)mod2)xor((A+C)mod2)=(B+C)mod2

显然,当 A=B=C=0 时上式成立,ABC 增加 1 并不会改变上述等式。

FWT[A]i=ij=0Ajij=1Aj,证明如下:

FWT[A]iFWT[B]i=(ij=0Ajij=1Aj)(ik=0Bkik=1Bk)=(ij=0Ajik=0Bk+ij=1Ajik=1Bk)(ij=0Ajik=1Bk+ij=1Ajik=0Bk)=(jk)i=0AjBk(jk)i=1AjBk=FWT[C]i

inline void FWT_XOR(int *A) {
    for (int len = 2; len <= (1 << n); len *= 2)
        for (int x = 0; x < (1 << n); x += len)
            for (int i = x; i < x + len / 2; ++ i) {
                A[i] = (A[i] + A[i + len / 2]) % mod;
                A[i + len / 2] = (A[i] - 2 * A[i + len / 2]) % mod;
            }
}

inline void IFWT_XOR(int *A) {
    for (int len = (1 << n); len >= 2; len /= 2)
        for (int x = 0; x < (1 << n); x += len)
            for (int i = x; i < x + len / 2; ++ i) {
                A[i + len / 2] = 1ll * (A[i] - A[i + len / 2]) 
                                     * quick_pow(2, mod - 2) % mod;
                A[i] = (A[i] - A[i + len / 2]) % mod;
            }
}

同或

若我们令 xy 表示 xy 中 1 数量的奇偶性,即 xy=popcnt(xy)mod2

FWT[A]i=ij=0Ajij=1Aj

posted @   chzhc  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
levels of contents
点击右上角即可分享
微信分享提示