\(\text {FWT}\) 学习笔记

正常项的\(\text {FWT}\)

在\(\text {OI}\)中,我们经常会碰到这种问题:

  • 给出一个长度为\(n\)的序列\(a_{1,2,...,n},b_{1,2,...,n}\),求出
\[c_k=\sum_{i\oplus j=k}a_i b_j
\]

其中\(\oplus\)是定义的一种二进制下的运算。

对于这种问题,我们有一种通用的方法,我们称之为\(\text {FWT}\)。

我们考虑对于一个\(A\)构造一个\(FWT\)变换序列,满足:

\[\forall A\times B=C,FWT[A]\star FWT[B]=FWT[C]
\]

其中\(\times\)就是上文定义的卷积,\(\star\)是按位乘法。

我们考虑定义一种二进制运算的函数\(c(i,j)\),满足:

\[FWT[A]_i=\sum_{j=0}^{n} c(i,j) A_j
\]

于是,我们可以得到:

若存在:

\[C=A\times B
\]

则有:

\[FWT[C]_i=\sum_{j=0}^{n} c(i,j)\sum_{k\oplus d=j} A_kB_d
\]
\[=\sum_{j=0}^{n} \sum_{k\oplus d=j} c(i,k\oplus d) A_k B_d
\]

而我们根据\(FWT\)的定义我们又可以得到:

\[FWT[C]_i=FWT[A]_i\times FWT[B]_i=(\sum_{j=0}^{n} c(i,j)A_j)\times (\sum_{j=0}^{n} c(i,j)B_j)
\]
\[=\sum_{j=0}^{n} \sum_{k=0}^{n} c(i,j) c(i,k)A_j B_k
\]

于是,我们就可以得到:

\[c(i,j)c(i,k)=c(i,j\oplus k)
\]

不过因为是在二进制下的运算,所以一般构造的话都会满足

\[i=(i_1i_2...i_n)_2
\]

则满足:

\[c(i,j)=c(i_1,j_1)c(i_2,j_2)...c(i_n,j_n)
\]

于是,我们只需要知道\(c(0/1,0/1)\)即可。

但是,我们现在仅仅可以在\(\Theta(n^2)\)的时间复杂度内求出和转换\(FWT[A]\),显然不能满足我们的对优秀的时间的渴求。

我们想一下在\(\text {FFT}\)中,我们是如何做到\(\Theta(n\log n)\)转换的?分治!!!我们在\(\text {FWT}\)中也可以用类似的方法。

我们考虑对于当前的\(FWT[A]_i\)应该如何求出。

可以得到:

\[FWT[A]_i=\sum_{j=0}^{n} c(i,j)A_j
\]
\[=\sum_{j=0}^{n/2-1} c(i_1,0) A_j+\sum_{j=n/2}^{n} c(i_1,1)A_j
\]
\[=c(i_1,0)FWT[A_0]_i+c(i_1,1)FWT[A_1]_i
\]

其中\(FWT[A_0/A_1]\)就是子集的一个变换,与\(\text {FFT}\)类似。

我们发现如果我们构造转移矩阵:

\[\text {mat}=\begin{bmatrix}c_{0,0} ,c_{0,1}\\ c_{1,0},c_{1,1} \end{bmatrix}
\]

其实\(A\to FWT[A]\)每一次变换就是乘上\(\text {mat}\),那么\(FWT[A]\to A\)就是乘上\(\text {mat}\)的逆矩阵。逆矩阵直接手动构造即可。

一些例子

\(\wedge\)

对于并卷积,我们可以构造\(c(i,j)=[i|j]\),其中\([i|j]\)表示的是二进制下的\(i\)是二进制下的\(j\)的子集(每一位\(0/1\)相当于该元素是否在当前集合出现)。

\(\vee\)

对于或卷积,我们可以构造\(c(i,j)=[j|i]\)。

\(\oplus\)

对于异或卷积,我们可以构造\(c(i,j)=(-1)^{|i\wedge j|}\)。

模板题

就是上面三种运算的总和,代码戳这里打开

非模板的一些例子

CF449D Jzzhu and Numbers

CF1119H Triple + 题解 link

\(\text {FST}\)

我们需要解决这样一个问题:

  • 给出一个长度为\(n\)的序列\(a_{1,2,...,n},b_{1,2,...,n}\),求出:
\[c_i=\sum_{j\vee k=i,j\wedge k=0} a_j b_k
\]

对于这个问题,如果没有\(j\wedge k=0\)的话,这就是一个板的\(\text {FWT}\) \(\vee\)运算。我们发现其实\(j\wedge k=0\)的条件就相当于\(|j|+|k|=|j\vee k|\),于是,我们可以设二维数组\(f_i\),我们可以设转移式:

\[f_i=\sum_{j=0}^{i} h_j w_{i-j}
\]

其中\(h_{i,j}=[|j|=i]a_j,w_{i,j}=[|j|=i]b_j\)。

很显然,最后的\(c_i=f_{|i|,i}\)。

于是,我们就可以在\(\Theta(n\log^ 2 n)\)的时间复杂度内解决这个问题。

代码戳这里打开

\(k\)进制下的\(\text {FWT}\)

我们发现上面的这个东西其实都是在\(2\)进制下面计算的,那么如果我们要拓展到\(k\)进制我们应该怎么办呢?

很显然,我们应该定义广义的\(\wedge,\vee,\oplus\)。

  • $\wedge $

在\(k\)进制下,定义\(a\wedge b=\min\{a,b\}\)

  • \(\vee\)

在\(k\)进制下,定义\(a\vee b=\max\{a,b\}\)

  • \(\oplus\)

在\(k\)进制下,定义\(a\oplus b=(a+b)\bmod k\)

因为\(\wedge,\vee\)不是很常用,所以这里着重介绍一下\(\oplus\)。

我们要考虑如何构造\(c(i,j)\),我们发现我们需要满足:

\[c(i,j)c(i,k)=c(i,(j+k)\bmod k)
\]

我们在脑中想一下,诶,似乎单位根满足这个条件诶!

于是,我们可以构造矩阵:

\[\begin{bmatrix}1&1&1&\cdots &1\\1&w_k^1&w_k^2&\cdots&w_k^{k-1}\\ 1&w_k^2&w_k^4&\cdots&w_k^{2(k-1)} \\ \vdots&\vdots& \vdots&\ddots &\vdots\\ 1&w_k^{k-1}&w_k^{2(k-1)}&\cdots&w_k^{(k-1)(k-1)}\end{bmatrix}
\]

而它的逆矩阵就是:

\[\frac{1}{k}\begin{bmatrix}1&1&1&\cdots &1\\1&w_k^{-1}&w_k^{-2}&\cdots&w_k^{-(k-1)}\\ 1&w_k^{-2}&w_k^{-4}&\cdots&w_k^{-2(k-1)} \\ \vdots&\vdots& \vdots&\ddots &\vdots\\ 1&w_k^{-(k-1)}&w_k^{-2(k-1)}&\cdots&w_k^{-(k-1)(k-1)}\end{bmatrix}
\]

一些例题

CF1103E Radix sum+题解 link

随机推荐

  1. assign()与create()的区别

    Q:assign()与create()的区别? A:let obj = Object.assign(targetObj, -sourceObj) 作用:将一个或多个源对象自身的可枚举属性与目标对象的属 ...

  2. JS 之 每日一题 之 算法 ( 有多少小于当前数字的数字 )

    给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目. 换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 ...

  3. 字符串截取子串(Java substring , indexOf)

    前言 因为之前java课设做的是股票分析系统,我找的接口返回的是一个.csv文件,因为这种文件里面的数据是以逗号分隔的,所以要对数据进行分析的时候需要截取子串,并且以逗号作为截取的标志.所以接下来就说 ...

  4. 揭秘盒马鲜生 Android 短视频秒播优化方案

    短视频作为内容重要的承载方式,是吸引用户的重点,短视频的内容与体验直接关系到用户是否愿意长时停留.因此,体验的优化就显得尤为重要.上一篇我们分享了 iOS 短视频秒播优化,这篇我们来聊聊 Androi ...

  5. LeetCode通关:通过排序一次秒杀五道题,舒服!

    刷题路线参考:https://github.com/chefyuan/algorithm-base 大家好,我是拿输出博客督促自己刷题的老三,前面学习了十大排序:万字长文|十大基本排序,一次搞定!,接 ...

  6. K8S——Pod

    一.Pod概念 二.Pod存在的意义 三.Pod的实现机制 四.Pod镜像拉取策略 五.Pod资源限制 六.Pod重启机制 七.Pod的健康检查 八.Pod调度策略(创建Pod流程)

  7. Qt 程序发布以及打包成exe安装包

    一.简述 Qt 项目开发完成之后,需要打包发布程序,而因为用户电脑上没有 Qt 配置环境,所以需要将 release 生成的 exe 文件和所依赖的 dll 文件复制到一个文件夹中,然后再用 Inno ...

  8. 第三课:GDB 常用的调试命令概览

    先给出一个常用命令的列表,后面会结合具体的例子详细介绍每个命令的用法. 命令名称 命令缩写 命令说明 run r 运行一个程序 continue c 让暂停的程序继续运行 next n 运行到下一行 ...

  9. Vue CSS模拟菜单点击变色

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  10. 放码来战!HMS Core线上Codelabs挑战赛正式开始

    亲爱的开发者,在1024程序员节即将到来之际,HMS Core准备了一场线上Codelabs挑战赛,现向你发出诚挚邀请,希望你能将新奇的想法和对产品的思考融入代码,用技术与世界对话. HMS Core ...