位运算卷积(FWT)
本文大量参考了:
- 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∑nc(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∑nc(i,j)A[j])(j=0∑nc(i,j)B[j])j=0∑nk=0∑nc(i,j)c(i,k)A[j]B[k]j=0∑nk=0∑nc(i,j)c(i,k)A[j]B[k]=FWT(C)[i]=(j=0∑nc(i,j)C[j])=j=0∑nc(i,j)a⊕b=j∑A[a]B[b]=j=0∑nk=0∑nc(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,1B⋮An,1B⋯⋱⋯A1,nB⋮An,nB⎦⎥⎤
也就是说 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−1c1(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−1c1(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,1B′⋮An,1B′⋯⋱⋯A1,nB′⋮An,nB′⎦⎥⎤∣∣∣∣∣∣∣
然后再把每 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 AckA,其中 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−1A1 和 ck−1A2c_{k-1}A_2ck−1A2 就能 O(2k)O(2^k)O(2k) 求出 ckAc_kAckA 了。
于是就可以分治。具体来说,在第 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−1Al∼mid 和 ck−1Amid+1∼rc_{k-1}A_{mid+1\sim r}ck−1Amid+1∼r 一起 O(2k)O(2^k)O(2k) 推导得到 ckAl∼rc_kA_{l\sim r}ckAl∼r。
时间复杂度 O(nlogn)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=[1101]。
And 卷积
类似,得到 c1=[0111]c_1=\begin{bmatrix}0&1\\1&1\end{bmatrix}c1=[0111]。
Xor 卷积
类似,得到 c1=[111−1]c_1=\begin{bmatrix}1&1\\1&-1\end{bmatrix}c1=[111−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−1c(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}ctAl∼r。于是每一轮的时间复杂度均为 O(kn)O(kn)O(kn),总时间复杂度 O(nklogkn)O(nk\log_kn)O(nklogkn)。
模 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}⎣⎡1111011100110001⎦⎤ 这种方式,其逆为 [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−10001−10001−10001⎦⎤。
发现其本质上就是前缀和及差分,所以单次求 ctAl∼rc_tA_{l\sim r}ctAl∼r 的时间可以从 O(k⋅kt)O(k\cdot k^t)O(k⋅kt) 优化到 O(kt)O(k^t)O(kt)。总时间复杂度降为 O(nlogkn)O(n\log_kn)O(nlogkn)。
从更宏观的角度来说,这个过程就是在做一个高维前缀和(每一轮做了一位的前缀和)以及高维差分(每一轮做了一位的差分)。
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)相关推荐
- 【OpenCV 例程200篇】20. 图像的按位运算
[OpenCV 例程200篇]20. 图像的按位运算 欢迎关注 『OpenCV 例程200篇』 系列,持续更新中 欢迎关注 『Python小白的OpenCV学习课』 系列,持续更新中 函数 cv2.b ...
- python中不同进制的整数之间可以直接运算_Python 进制转换、位运算
一.进制转换 编程用十进制,十进制转换为二进制.八进制.十六进制 In [135]: bin(23) Out[135]: '0b10111' In [136]: oct(23) Out[136]: ' ...
- python isodd()判断奇偶_位运算(1的个数;2.判断奇偶)
1. 1的个数 int NumberOf1(intn){int count = 0;while(n) {++count; n=(n-1)&n; } } 同样一个问题,位运算可以提高程序的运行效 ...
- python 整数逆位运算_python训练营:注释、运算符、数据类型与位运算
天学习的内容整理成脑图如下,其中带☆的是需要重点掌握的模糊知识点,需要加强训练和记忆. 二.具体学习内容 2.1 注释 2.1.1 多行注释 2.1.2 长字符串注释 2.2 运算符 2.2.1 算术 ...
- 洛谷P1896 [SCOI2005]互不侵犯 状压dp+位运算
题目链接:https://www.luogu.org/problem/P1896 题意:n*n的格子填数,每个数填放位置的周围(8个)不能有其他的数 n<=9 ,矩形状压 f[i][j][s], ...
- mysql 使用位运算
如果你不知道什么是位运算的话, 那么请你先去看看基础的C语言教程吧. 与运算 a & b , 或运算 a | b , 异或运算 a ^ b , 或者 你也可以将 与运算理解为 + 法 例 ...
- 位运算+取某一位+java_Java位运算小节
2019新春支付宝红包技术大揭秘在线峰会将于03-07日开始,点击这里报名届时即可参与大牛互动. 位运算表达式由操作数和位运算符组成,实现对整数类型的二进制数进行位运算.位运算符可以分为逻辑运算符(包 ...
- 进制转换 位运算(包括补码、原码、反码、~0等一些零碎东西一次说清)
我发现网上关于标题上的内容介绍的都很零碎,因此为了方便查找.也为了本人对这一部分的充分理解,就想着写一篇这样的博客(我分成了几个部分,以便查找): 一.进制转换 让我们先来看看各个进制的定义: 十进制 ...
- (转)C语言位运算详解
地址:http://www.cnblogs.com/911/archive/2008/05/20/1203477.html C语言位运算详解 作者:911 说明:本文参考了http://www2.ts ...
最新文章
- 800万中文词,腾讯AI Lab开源大规模NLP数据集
- 1亿数据 redis 内存_redis 存1亿数据库
- Python- 反射 及部份内置属性方法
- Android之使用IDA Pro静态分析so文件
- 庚顿数据:实时数据库赋能工业互联网
- python元胞自动机模拟交通_基于立体网格的放射性污染物扩散过程模拟与表达
- SparkSql 数据类型转换
- 匹配 边覆盖 独立集 顶点覆盖
- java统计字数_Java 8的字数统计
- 图表设计-远不止“好看”这么简单
- 国家级赛事正式开赛 | 2019数字中国创新大赛上线
- python怎么学比较快,怎样快速学会python
- 2023java面试看完这篇笔记薪资和offer稳了!
- 数据结构(六):伸展树简介
- siggraph_Siggraph的统一性
- git 使用meld 进行文本对比
- SAP中在FS00中显示组科目表(集团科目表)
- 数据项组成数据元素,数据元素组成数据
- php自动收录导航程序,最新自动收录自带查反链导航源码
- 电脑黑屏只有鼠标能动怎么办???
热门文章
- 脂肪酸补品行业调研报告 - 市场现状分析与发展前景预测
- 叠氮5-FAM,5-Carboxyfluorescein-azide,510758-23-3
- asp.net大学生家教管理系统
- 从零开始学USB(十八、USB的class)
- 为什么不能自己DIY一个iconfont库?
- oracle vm virtualbox 失败,Oracle VM VirtualBox启动提示“创建COM对象失败”
- 【元宇宙欧米说】蓝魂,web3专用linktree
- Top-1 accuracy和Top-5 accuracy的概念及理解
- 自己动手训练word2vec模型
- 端午“沉浸式云旅游”怎么玩?即构助力“直播+”新场景落地