本文大量参考了:

  • command_block 的博客:位运算卷积(FWT) & 集合幂级数

FWT 概论

定义位运算卷积:C[k]=∑i⊕j=kA[i]B[j]C[k]=\sum\limits_{i\oplus j=k}A[i]B[j]C[k]=i⊕j=k∑​A[i]B[j],记作 C=A∗BC=A*BC=A∗B,其中 $\oplus $ 为某一位运算。

设 A,BA,BA,B 下标的范围都是 [0,n−1][0,n-1][0,n−1] 且满足 nnn 是 222 的幂,那么卷出来 CCC 的下标范围也是 [0,n−1][0,n-1][0,n−1]。

为了加速位运算卷积,我们尝试构造一个像 FFT 一样的算法,把卷积转化为直接点积。

设转化矩阵为 ccc,即 FWT(A)=cAFWT(A)=cAFWT(A)=cA,FWT(A)[i]=∑j=0nc(i,j)A[j]FWT(A)[i]=\sum\limits_{j=0}^nc(i,j)A[j]FWT(A)[i]=j=0∑n​c(i,j)A[j]。使其满足:

FWT(A)[i]⋅FWT(B)[i]=FWT(C)[i](∑j=0nc(i,j)A[j])(∑j=0nc(i,j)B[j])=(∑j=0nc(i,j)C[j])∑j=0n∑k=0nc(i,j)c(i,k)A[j]B[k]=∑j=0nc(i,j)∑a⊕b=jA[a]B[b]∑j=0n∑k=0nc(i,j)c(i,k)A[j]B[k]=∑j=0n∑k=0nc(i,j⊕k)A[j]B[k]\begin{aligned}FWT(A)[i]\cdot FWT(B)[i]&=FWT(C)[i]\\\left(\sum_{j=0}^nc(i,j)A[j]\right)\left(\sum_{j=0}^nc(i,j)B[j]\right)&=\left(\sum_{j=0}^nc(i,j)C[j]\right)\\\sum_{j=0}^n\sum_{k=0}^nc(i,j)c(i,k)A[j]B[k]&=\sum_{j=0}^nc(i,j)\sum_{a\oplus b=j}A[a]B[b]\\\sum_{j=0}^n\sum_{k=0}^nc(i,j)c(i,k)A[j]B[k]&=\sum_{j=0}^n\sum_{k=0}^nc(i,j\oplus k)A[j]B[k]\end{aligned} FWT(A)[i]⋅FWT(B)[i](j=0∑n​c(i,j)A[j])(j=0∑n​c(i,j)B[j])j=0∑n​k=0∑n​c(i,j)c(i,k)A[j]B[k]j=0∑n​k=0∑n​c(i,j)c(i,k)A[j]B[k]​=FWT(C)[i]=(j=0∑n​c(i,j)C[j])=j=0∑n​c(i,j)a⊕b=j∑​A[a]B[b]=j=0∑n​k=0∑n​c(i,j⊕k)A[j]B[k]​

只要满足 c(i,j)c(i,k)=c(i,j⊕k)c(i,j)c(i,k)=c(i,j\oplus k)c(i,j)c(i,k)=c(i,j⊕k) 即可让上式成立。

事实上我们也可以证明出必要性:由于这个式子需要对任意的 A,BA,BA,B 都成立(也就是说 A[1],⋯,A[n],B[1],⋯,B[n]A[1],\cdots,A[n],B[1],\cdots,B[n]A[1],⋯,A[n],B[1],⋯,B[n] 可以看成是 2n2n2n 个独立的变量),那么我们就必须要满足 c(i,j)c(i,k)=c(i,j⊕k)c(i,j)c(i,k)=c(i,j\oplus k)c(i,j)c(i,k)=c(i,j⊕k)。

你可能会发现这个条件和 iii 并没有关系,那你可能会想:能不能先找到一个数组 c′c'c′ 满足 c′(j)c′(k)=c′(j⊕k)c'(j)c'(k)=c'(j\oplus k)c′(j)c′(k)=c′(j⊕k),然后让所有的 c(i,j)c(i,j)c(i,j) 都直接赋值为 c′(j)c'(j)c′(j) 就好了呢?

肯定是不行的,为了保证我们得到 FWT(C)=c×CFWT(C)=c\times CFWT(C)=c×C 后能得回 CCC,我们还需要满足矩阵 ccc 有逆。而按刚刚的构造方法得到的矩阵 ccc 秩为 111,没有逆。

现在的问题是我们要构造出 nnn 种数组 c′c'c′ 使得它们都满足 c′(j)c′(k)=c′(j⊕k)c'(j)c'(k)=c'(j\oplus k)c′(j)c′(k)=c′(j⊕k),而且要求这 nnn 个数组拼起来得到的矩阵有逆。

一种巧妙的构造方式是:我们先构造出对于 n=2n=2n=2 时满足要求的矩阵,记为 c1c_1c1​。然后递推对于 n=2k(k>1)n=2^k(k>1)n=2k(k>1) 时满足的矩阵:ck=c1⊗ck−1c_k=c_1\otimes c_{k-1}ck​=c1​⊗ck−1​。

其中 ⊗\otimes⊗ 为克罗内克积:对于大小为 n×nn\times nn×n 的矩阵 AAA 和大小为 m×mm\times mm×m 的矩阵 BBB,它们的克罗内克积为:

A⊗B=[A1,1B⋯A1,nB⋮⋱⋮An,1B⋯An,nB]A\otimes B=\begin{bmatrix}A_{1,1}B&\cdots&A_{1,n}B\\\vdots &\ddots &\vdots\\A_{n,1}B&\cdots&A_{n,n}B\end{bmatrix} A⊗B=⎣⎢⎡​A1,1​B⋮An,1​B​⋯⋱⋯​A1,n​B⋮An,n​B​⎦⎥⎤​

也就是说 ckc_kck​ 为 c1c_1c1​ 的 kkk 级分形。设 n=2mn=2^mn=2m,最后取 cmc_{m}cm​ 即为我们想要的 ccc。

考虑这么做为什么是对的,我们需要证明两点:c(i,j)c(i,k)=c(i,j⊕k)c(i,j)c(i,k)=c(i,j\oplus k)c(i,j)c(i,k)=c(i,j⊕k) 和矩阵 ccc 有逆。

  • 定理 1:c(i,j)c(i,k)=c(i,j⊕k)c(i,j)c(i,k)=c(i,j\oplus k)c(i,j)c(i,k)=c(i,j⊕k)。

    证明:设 xtx_txt​ 表示 xxx 在二进制下的第 ttt 位,通过构造方式不难证明出 c(i,j)=∏i=0m−1c1(it,jt)c(i,j)=\prod\limits_{i=0}^{m-1} c_1(i_t,j_t)c(i,j)=i=0∏m−1​c1​(it​,jt​)。而矩阵 c1c_1c1​ 是满足条件的。

    c(i,j)=∏i=0m−1c1(it,jt)c(i,j)=\prod\limits_{i=0}^{m-1} c_1(i_t,j_t)c(i,j)=i=0∏m−1​c1​(it​,jt​) 这条式子是非常好的记忆方法:即我们先找出对 n=2n=2n=2 满足要求的矩阵,那么 c(i,j)c(i,j)c(i,j) 就是 i,ji,ji,j 拆位后各位的 ccc 的乘积。

在证明矩阵 ccc 有逆之前,我们需要了解一个有关克罗内克积的引理。

  • 引理 1:对于大小为 n×nn\times nn×n 的矩阵 AAA 和大小为 m×mm\times mm×m 的矩阵 BBB,设它们的克罗内克积为 C=A⊗BC=A\otimes BC=A⊗B,那么有:

    ∣C∣=∣A∣m∣B∣n|C|=|A|^m|B|^n ∣C∣=∣A∣m∣B∣n

    证明:考虑使用高斯消元法来求解行列式,那么 ∣A∣|A|∣A∣ 的含义就是:(−1)μ(A)D(A)(-1)^{\mu(A)}D(A)(−1)μ(A)D(A),其中 D(A)D(A)D(A) 表示将 AAA 消为上三角矩阵后对角线上元素的乘积,μ(A)\mu(A)μ(A) 表示消元过程中使用操作”交换两行“的次数的奇偶性。

    现在考虑对 CCC 进行高斯消元,我们可以每 mmm 行一组按对 BBB 消元的方式消元,共 nnn 组,得到:(其中 B′B'B′ 为将矩阵 BBB 消元后得到的上三角矩阵)

    ∣C∣=(−1)n⋅μ(B)∣[A1,1B′⋯A1,nB′⋮⋱⋮An,1B′⋯An,nB′]∣|C|=(-1)^{n\cdot \mu(B)}\left|\begin{bmatrix}A_{1,1}B'&\cdots&A_{1,n}B'\\\vdots &\ddots &\vdots\\A_{n,1}B'&\cdots&A_{n,n}B'\end{bmatrix}\right| ∣C∣=(−1)n⋅μ(B)∣∣∣∣∣∣∣​⎣⎢⎡​A1,1​B′⋮An,1​B′​⋯⋱⋯​A1,n​B′⋮An,n​B′​⎦⎥⎤​∣∣∣∣∣∣∣​

    然后再把每 m×mm\times mm×m 的矩阵看成一格,然后用对 AAA 消元的方式对剩下的这个 n×nn\times nn×n 格的矩阵消元,得到:(其中 A′A'A′ 为将矩阵 AAA 消元后得到的上三角矩阵)

    ∣C∣=(−1)n⋅μ(B)(−1)m⋅μ(A)∣[A1,1′B′⋯A1,n′B′⋮⋱⋮An,1′B′⋯An,n′B′]∣|C|=(-1)^{n\cdot \mu(B)}(-1)^{m\cdot \mu(A)}\left|\begin{bmatrix}A'_{1,1}B'&\cdots&A'_{1,n}B'\\\vdots &\ddots &\vdots\\A'_{n,1}B'&\cdots&A'_{n,n}B'\end{bmatrix}\right| ∣C∣=(−1)n⋅μ(B)(−1)m⋅μ(A)∣∣∣∣∣∣∣​⎣⎢⎡​A1,1′​B′⋮An,1′​B′​⋯⋱⋯​A1,n′​B′⋮An,n′​B′​⎦⎥⎤​∣∣∣∣∣∣∣​

    最后得到的这个矩阵是一个上三角矩阵,它的对角线的乘积为 D(A)mD(B)nD(A)^mD(B)^nD(A)mD(B)n,于是:

    ∣C∣=(−1)n⋅μ(B)×(−1)m⋅μ(A)×D(A)m×D(B)n=((−1)μ(A)D(A))m((−1)μ(B)D(B))n=∣A∣m∣B∣n\begin{aligned}|C|&=(-1)^{n\cdot \mu(B)}\times (-1)^{m\cdot \mu(A)}\times D(A)^m\times D(B)^n\\&=\left((-1)^{\mu(A)}D(A)\right)^m\left((-1)^{\mu(B)}D(B)\right)^n\\&=|A|^m|B|^n\end{aligned} ∣C∣​=(−1)n⋅μ(B)×(−1)m⋅μ(A)×D(A)m×D(B)n=((−1)μ(A)D(A))m((−1)μ(B)D(B))n=∣A∣m∣B∣n​

  • 定理 2:矩阵 ccc 有逆。

    证明:矩阵有逆等价于矩阵行列式不为 000。初始时 c1c_1c1​ 满足条件,即 c1c_1c1​ 行列式不为 000。根据引理1可以归纳证明对于任意 kkk 都有 ckc_kck​ 行列式不为 000。

至此,我们证明了我们所构造出来的 ccc 是满足条件的转化矩阵。

而用这种构造方式构造出的 ccc 的一个好处是它能用分治加速转化的过程。

假设我们现在要求 ckAc_k Ack​A,其中 AAA 的下标范围为 [0,2k−1][0,2^k-1][0,2k−1]:



根据构造方式,我们可以将 ckc_kck​ 分成四块,每块都是 ck−1c_{k-1}ck−1​ 的若干倍(具体来说,倍数分别为 c1c_1c1​ 中对应的的四个数)。那么我们也将 AAA 分成两半 A1,A2A_1,A_2A1​,A2​,那么我们只需要求出 ck−1A1c_{k-1}A_1ck−1​A1​ 和 ck−1A2c_{k-1}A_2ck−1​A2​ 就能 O(2k)O(2^k)O(2k) 求出 ckAc_kAck​A 了。

于是就可以分治。具体来说,在第 kkk 轮时,我们将 0∼n−10\sim n-10∼n−1 每 2k2^k2k 分成一块,然后对于每一段 l∼r(r−l+1=2k)l\sim r(r-l+1=2^k)l∼r(r−l+1=2k),用 ck−1Al∼midc_{k-1}A_{l\sim mid}ck−1​Al∼mid​ 和 ck−1Amid+1∼rc_{k-1}A_{mid+1\sim r}ck−1​Amid+1∼r​ 一起 O(2k)O(2^k)O(2k) 推导得到 ckAl∼rc_kA_{l\sim r}ck​Al∼r​。

时间复杂度 O(nlog⁡n)O(n\log n)O(nlogn)。

下面举几种位运算的例子。

Or 卷积

相当于要求两种线性无关的 ccc 使得它们都满足 c(j)c(k)=c(j∣k)c(j)c(k)=c(j|k)c(j)c(k)=c(j∣k)。我们可以先求出所有的可能的 ccc:(记 a=c(0),b=c(1)a=c(0),b=c(1)a=c(0),b=c(1))

{a⋅a=aa⋅b=bb⋅b=b\begin{cases}a\cdot a=a\\a\cdot b=b\\b\cdot b=b\end{cases} ⎩⎪⎨⎪⎧​a⋅a=aa⋅b=bb⋅b=b​

得到 333 组解:{a=0b=0,{a=1b=0,{a=1b=1\begin{cases}a=0\\b=0\end{cases},\begin{cases}a=1\\b=0\end{cases},\begin{cases}a=1\\b=1\end{cases}{a=0b=0​,{a=1b=0​,{a=1b=1​,唯一的方法是取后两组组成矩阵 c1=[1011]c_1=\begin{bmatrix}1&0\\1&1\end{bmatrix}c1​=[11​01​]。

And 卷积

类似,得到 c1=[0111]c_1=\begin{bmatrix}0&1\\1&1\end{bmatrix}c1​=[01​11​]。

Xor 卷积

类似,得到 c1=[111−1]c_1=\begin{bmatrix}1&1\\1&-1\end{bmatrix}c1​=[11​1−1​]。

位值域扩展

注意到:or 卷积为模 222 意义下的高维 max 卷积,and 卷积为模 222 意义下的高维 min 卷积,xor 卷积为模 222 意义下的高维加法卷积。

事实上,我们也可以用类似的方法实现模 kkk 意义下的高维 max/min/加法 卷积。

设 n=kbn=k^bn=kb。我们同样先构造出对于 n=kn=kn=k 时满足要求的 k×kk\times kk×k 矩阵 c1c_1c1​,然后 c1c_1c1​ 的 bbb 级分形即为我们要的转化矩阵 ccc。同样,我们只需要证明 c(i,p)c(i,q)=c(i,p⊕q)c(i,p)c(i,q)=c(i,p\oplus q)c(i,p)c(i,q)=c(i,p⊕q) 且矩阵 ccc 有逆。

对于前者,我们类似地可以得到 c(i,j)=∏t=0b−1c(it,jt)c(i,j)=\prod_{t=0}^{b-1} c(i_t,j_t)c(i,j)=∏t=0b−1​c(it​,jt​),其中 iti_tit​ 为 iii 在 kkk 进制下第 ttt 位的值。那么就易证了。

而关于矩阵有逆的证明则没有任何变化,因为过程中我们只用到了克罗内克积的性质。

所以按照该方法构造出来的矩阵 ccc 仍然是满足要求的。

仍然是分治加速求 ccc。在第 ttt 轮时,我们将序列每 ktk^tkt 分成一段,一段内用 O(k⋅kt)O(k\cdot k^t)O(k⋅kt) 的时间求出 ctAl∼rc_tA_{l\sim r}ct​Al∼r​。于是每一轮的时间复杂度均为 O(kn)O(kn)O(kn),总时间复杂度 O(nklog⁡kn)O(nk\log_kn)O(nklogk​n)。

模 kkk 意义下的 max/min 卷积

先讲 max 卷积的情况。我们需要构造 kkk 组线性无关的 ccc 使得它们都满足 c(p)c(q)=c(max⁡(p,q))c(p)c(q)=c(\max(p,q))c(p)c(q)=c(max(p,q))。

取 p=qp=qp=q 我们首先可以确定 ccc 的值域为 {0,1}\{0,1\}{0,1}。然后发现 c(p)c(q)=c(max⁡(p,q))c(p)c(q)=c(\max(p,q))c(p)c(q)=c(max(p,q)) 说明 ccc 数组肯定形如前一段是 111 后一段是 000。那么除了全 000 之外恰好就有 kkk 组 ccc。把它们按任意顺序拼成一个矩阵均可。

为了方便,一般采用形如 [1000110011101111]\scriptsize\begin{bmatrix}1&0&0&0\\1&1&0&0\\1&1&1&0\\1&1&1&1\end{bmatrix}⎣⎡​1111​0111​0011​0001​⎦⎤​ 这种方式,其逆为 [1000−11000−11000−11]\scriptsize\begin{bmatrix}1&0&0&0\\-1&1&0&0\\0&-1&1&0\\0&0&-1&1\end{bmatrix}⎣⎡​1−100​01−10​001−1​0001​⎦⎤​。

发现其本质上就是前缀和及差分,所以单次求 ctAl∼rc_tA_{l\sim r}ct​Al∼r​ 的时间可以从 O(k⋅kt)O(k\cdot k^t)O(k⋅kt) 优化到 O(kt)O(k^t)O(kt)。总时间复杂度降为 O(nlog⁡kn)O(n\log_kn)O(nlogk​n)。

从更宏观的角度来说,这个过程就是在做一个高维前缀和(每一轮做了一位的前缀和)以及高维差分(每一轮做了一位的差分)。

min 卷积也是类似的,只不过 ccc 数组肯定形如前一段是 000 后一段是 111 罢了。

模 kkk 意义下的加法卷积

我们需要构造 kkk 组线性无关的 ccc 使得它们都满足 c(p)c(q)=c((p+q)modk)c(p)c(q)=c((p+q)\bmod k)c(p)c(q)=c((p+q)modk)。

直接令 c1c_1c1​ 为 FFT 中的范德蒙德矩阵即可,即 c(i,j)=wkijc(i,j)=w_k^{ij}c(i,j)=wkij​。

但在模意义下可能不存在 kkk 次单位根。

咕。

位运算卷积(FWT)相关推荐

  1. 【OpenCV 例程200篇】20. 图像的按位运算

    [OpenCV 例程200篇]20. 图像的按位运算 欢迎关注 『OpenCV 例程200篇』 系列,持续更新中 欢迎关注 『Python小白的OpenCV学习课』 系列,持续更新中 函数 cv2.b ...

  2. python中不同进制的整数之间可以直接运算_Python 进制转换、位运算

    一.进制转换 编程用十进制,十进制转换为二进制.八进制.十六进制 In [135]: bin(23) Out[135]: '0b10111' In [136]: oct(23) Out[136]: ' ...

  3. python isodd()判断奇偶_位运算(1的个数;2.判断奇偶)

    1. 1的个数 int NumberOf1(intn){int count = 0;while(n) {++count; n=(n-1)&n; } } 同样一个问题,位运算可以提高程序的运行效 ...

  4. python 整数逆位运算_python训练营:注释、运算符、数据类型与位运算

    天学习的内容整理成脑图如下,其中带☆的是需要重点掌握的模糊知识点,需要加强训练和记忆. 二.具体学习内容 2.1 注释 2.1.1 多行注释 2.1.2 长字符串注释 2.2 运算符 2.2.1 算术 ...

  5. 洛谷P1896 [SCOI2005]互不侵犯 状压dp+位运算

    题目链接:https://www.luogu.org/problem/P1896 题意:n*n的格子填数,每个数填放位置的周围(8个)不能有其他的数 n<=9 ,矩形状压 f[i][j][s], ...

  6. mysql 使用位运算

    如果你不知道什么是位运算的话, 那么请你先去看看基础的C语言教程吧. 与运算 a & b  , 或运算 a | b ,  异或运算 a ^ b , 或者 你也可以将 与运算理解为 + 法  例 ...

  7. 位运算+取某一位+java_Java位运算小节

    2019新春支付宝红包技术大揭秘在线峰会将于03-07日开始,点击这里报名届时即可参与大牛互动. 位运算表达式由操作数和位运算符组成,实现对整数类型的二进制数进行位运算.位运算符可以分为逻辑运算符(包 ...

  8. 进制转换 位运算(包括补码、原码、反码、~0等一些零碎东西一次说清)

    我发现网上关于标题上的内容介绍的都很零碎,因此为了方便查找.也为了本人对这一部分的充分理解,就想着写一篇这样的博客(我分成了几个部分,以便查找): 一.进制转换 让我们先来看看各个进制的定义: 十进制 ...

  9. (转)C语言位运算详解

    地址:http://www.cnblogs.com/911/archive/2008/05/20/1203477.html C语言位运算详解 作者:911 说明:本文参考了http://www2.ts ...

最新文章

  1. 800万中文词,腾讯AI Lab开源大规模NLP数据集
  2. 1亿数据 redis 内存_redis 存1亿数据库
  3. Python- 反射 及部份内置属性方法
  4. Android之使用IDA Pro静态分析so文件
  5. 庚顿数据:实时数据库赋能工业互联网
  6. python元胞自动机模拟交通_基于立体网格的放射性污染物扩散过程模拟与表达
  7. SparkSql 数据类型转换
  8. 匹配 边覆盖 独立集 顶点覆盖
  9. java统计字数_Java 8的字数统计
  10. 图表设计-远不止“好看”这么简单
  11. 国家级赛事正式开赛 | 2019数字中国创新大赛上线
  12. python怎么学比较快,怎样快速学会python
  13. 2023java面试看完这篇笔记薪资和offer稳了!
  14. 数据结构(六):伸展树简介
  15. siggraph_Siggraph的统一性
  16. git 使用meld 进行文本对比
  17. SAP中在FS00中显示组科目表(集团科目表)
  18. 数据项组成数据元素,数据元素组成数据
  19. php自动收录导航程序,最新自动收录自带查反链导航源码
  20. 电脑黑屏只有鼠标能动怎么办???

热门文章

  1. 脂肪酸补品行业调研报告 - 市场现状分析与发展前景预测
  2. 叠氮5-FAM,5-Carboxyfluorescein-azide,510758-23-3
  3. asp.net大学生家教管理系统
  4. 从零开始学USB(十八、USB的class)
  5. 为什么不能自己DIY一个iconfont库?
  6. oracle vm virtualbox 失败,Oracle VM VirtualBox启动提示“创建COM对象失败”
  7. 【元宇宙欧米说】蓝魂,web3专用linktree
  8. Top-1 accuracy和Top-5 accuracy的概念及理解
  9. 自己动手训练word2vec模型
  10. 端午“沉浸式云旅游”怎么玩?即构助力“直播+”新场景落地