前言:

  $FWT$是用来处理位运算(异或、与、或)卷积的一种变换。位运算卷积是什么?形如$f[i]=\sum\limits_{j\oplus k==i}^{ }g[j]*h[k]$的卷积形式(其中$\oplus$为位运算)就是位运算卷积。如果暴力枚举的话,时间复杂度是$O(n^2)$,但运用$FWT$来解决就可达到$O(nlog_{n})$的时间复杂度。$FST$则是借助$FWT$来进行的对子集卷积的优化,相当于$FWT$的一个应用。

FWT

与卷积

对于与运算,有一个结论:$(i\&j)\&k==k<-->(i\&k==k)\&\&(j\&k==k)$。

那么我们就可以构造一个求父集和的函数$F(i)=\sum\limits_{j\&i==i}^{ }f(i)$,由此我们可以推出:

$G(k)*H(k)$

$=\sum\limits_{i\&k==k}^{ }g(i)\sum\limits_{j\&k==k}^{ }h(j)$

$=\sum\limits_{(i\&j)\&k==k}^{ }g(i)*h(j)$

$=\sum\limits_{t\&k==k}^{ }\sum\limits_{i\&j==t}^{ }g(i)*h(j)$

因为$f(t)=\sum\limits_{i\&j==t}^{ }g(i)*h(j)$,

所有上式$=\sum\limits_{t\&k==k}^{ }f(t)=F(k)$

因此我们只需要将$g,h$正变换成$G,H$,然后对应位相乘得到$F$后再将$F$逆变换回去即可得到$f$。

那么如何正变换?

以下面为例:

00 a

01 b

10 c

11 d

我们从最低位开始考虑,每次只考虑只有当前位不同的两个数之间的影响。显然求父集只有$1$会对$0$有贡献,因此我们将$01$的值加到$00$上,将$11$的值加到$10$上,再看下一位,同样将$11$的值加到$01$上,将$10$的值加到$00$上。这样最后$00$的值为$a+b+c+d$,$01$的值为$b+d$,$10$的值为$c+d$,$11$的值为$d$。同样逆变换就是将$1$的值从$0$上减掉即可。

附上代码

void fwt_and(int *a,int opt)
{for(int k=2;k<=n;k<<=1){for(int i=0,t=k>>1;i<n;i+=k){for(int j=i;j<i+t;j++){if(opt==1){a[j]=(a[j]+a[j+t])%mod;}else{a[j]=(a[j]-a[j+t]+mod)%mod;}}}}
}

或卷积

或卷积和与卷积类似,对于或卷积同样有结论:$(i|j)|k==k<-->(i|k==k)\&\&(j|k==k)$

这次我们需要构造一个求子集和的函数$G(i)=\sum\limits_{j|i==i}^{ }g(j)$,推导过程和与卷积类似。

对于正变换,显然只有$0$对$1$有贡献;对于逆变换,只需要将$0$的值从$1$中减掉即可。

附上代码

void fwt_or(int *a,int opt)
{for(int k=2;k<=n;k<<=1){for(int i=0,t=k>>1;i<n;i+=k){for(int j=i;j<i+t;j++){if(opt==1){a[j+t]=(a[j+t]+a[j])%mod;}else{a[j+t]=(a[j+t]-a[j]+mod)%mod;}}}}
}

异或卷积

对于异或卷积,我们设$bit(i)$代表$i$的二进制中$1$的奇偶性,因此有一个结论(这里异或用$\oplus$表示):$bit(i\&k)\oplus bit(j\&k)=bit((i\oplus j)\&k)$

对于原多项式$g$构造$G(i)=\sum\limits_{j=0}^{2^n-1}(-1)^{bit(j\&i)}g(j)$

开始推导:

$G(k)*H(k)$

$=\sum (-1)^{bit(i\&k)}g(i)\sum (-1)^{bit(j\&k)}h(j)$

$=\sum (-1)^{bit((i\oplus j)\& k)}g(i)*h(j)$

$=\sum (-1)^{bit(t\&k)}\sum\limits_{i\oplus j==t}^{ }g(i)*h(j)$

$=\sum (-1)^{bit(t\&k)}f(t)$

$=F(k)$

对于正变换,我们同样从最低位向最高位考虑,每次只考虑只有当前位不同的两个数之间的影响。对于每对$0$和$1$(设值分别为$a$和$b$),$0\&0=0$和$0\&1=0$都不会影响$bit$的值,所以$0$那个位置的值变成$a+b$;$1\&0=0$不会影响$bit$的值,但$1\&1=1$会影响$bit$的值(相当于在前面乘上一个$-1$的系数),因此$1$那个位置的值变成$a-b$。对于逆变换,相当于我们现在知道两个位置$x=a+b$,$y=a-b$,求$a$和$b$,可以得到$a=\frac{x+y}{2},b=\frac{x-y}{2}$。

附上代码

void fwt_xor(int *a,int opt)
{int tmp;for(int k=2;k<=n;k<<=1){for(int i=0,t=k>>1;i<n;i+=k){for(int j=i;j<i+t;j++){tmp=a[j];a[j]=(a[j]+a[j+t])%mod;a[j+t]=(tmp-a[j+t]+mod)%mod;if(opt==-1){a[j]=1ll*a[j]*inv%mod;a[j+t]=1ll*a[j+t]*inv%mod;}}}}
}

K进制异或卷积

可以发现二进制的异或运算相当于不进位加法即每一位对应相加后对$2$取模,而与运算相当于不进位乘法即每一位对应相乘后对$2$取模,$bit$相当于求二进制每一位的和对$2$取模。那么我们将这些在二进制下的运算扩展到$K$进制可以发现同样满足上述的结论,但对于从$g$求$G$的部分每个数前面的系数的底数是$-1$,显然这个系数不能扩展到$K$进制。那么我们现在就需要找一个系数$w$满足$w^0,w^1,w^2……w^{k-1}$都各不相同且$w^i=w^{i\%k}$。从$FFT$中我们知道了复数单位根这个东西,那么我们完全可以将$w$取$K$次单位根,这样就可以满足以上性质了!类比二进制亦或的正变换也可以得出$K$进制的正变换。

FST

$FST$通常用来优化一类子集$DP$,例如$f(S)=\sum g(T)*h(S-T)$,其中$T$是$S$的子集。

对于这个方程我们不能直接用$FWT$卷积,因为如果$g(i)*h(j)$会对$f(k)$有贡献就要求$i|j=k,i\&j=0$。

显然位运算卷积不能同时满足这两个要求,那么我们将方程变成二维表示$f[S][i]=\sum\limits_{j=1}^{i}\sum\limits_{a|b==S}^{ }g[a][j]*h[b][i-j]$

其中的第二维表示集合大小,对于$f[S][i]$只有当$i=|S|$时才有值,这样第一维保证并集为$S$,第二维保证交集为空集,所以其他不合法的状态不会影响答案。

这样我们就能对式子进行卷积:$F[S][i]=\sum\limits_{j=1}^{i}G[S][j]*H[S][i-j]$。求出每个$F$的值再$FWT$逆变换回去即可。

原题中的$f[S]$就是二维状态中的$f[S][|S|]$。

时间复杂度为$O(2^n*n^2)$。

转载于:https://www.cnblogs.com/Khada-Jhin/p/10005488.html

快速沃尔什变换(FWT)及K进制异或卷积快速子集变换(FST)讲解相关推荐

  1. 解题报告(一)快速沃尔什变换FWT(ACM / OI)超高质量题解

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量的题解和代码,题目难度不一 ...

  2. 解题报告(一)B、(CF453D) Little Pony and Elements of Harmony(FWT经典套路 + 任意模数 k 进制FWT + 快速幂)(2)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  3. LeetCode简单题之K 进制表示下的各位数字总和

    题目 给你一个整数 n(10 进制)和一个基数 k ,请你将 n 从 10 进制表示转换为 k 进制表示,计算并返回转换后各位数字的 总和 . 转换后,各位数字应当视作是 10 进制数字,且它们的总和 ...

  4. P1066 2^k进制数 NOIP 2006 提高组 第四题

    洛谷蓝题(点击跳转) 提高组 第四题 题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的 ...

  5. [NOIP2006] 提高组 洛谷P1066 2^k进制数

    题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. (3)将r转换为2进制数q后 ...

  6. LeetCode 1837. K 进制表示下的各位数字总和

    文章目录 1. 题目 2. 解题 1. 题目 给你一个整数 n(10 进制)和一个基数 k ,请你将 n 从 10 进制表示转换为 k 进制表示,计算并返回转换后各位数字的 总和 . 转换后,各位数字 ...

  7. 51 Nod 1116 K进制下的大数

    1116 K进制下的大数  基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题  收藏  关注 有一个字符串S,记录了一个大数,但不知这个大数是多少进制的,只知道这个数 ...

  8. P1066 2^k进制数

    传送门 好好看题 看懂了就不难了 在2^k进制下,一位一位看 每一位都有一些数可以填 除非是最左边一位,不然可以填的数最大都是 2^k-1 所以显然当填的位数为 i 时(不是最后一位),可能的选取方案 ...

  9. 将十进制正整数m转换成k进制(2≤k≤9)数的数字输出

    //给定程序的功能是将十进制正整数m转换成k进制(2≤k≤9)数的数字输出. //例如,若输入8和2,则应输出1000(即十进制数8转换成二进制表示是1000).请填空. #include <s ...

最新文章

  1. ios/mac command
  2. Flex 按钮添加图标
  3. java 类一定要声明成public_类和对象练习题
  4. 【前端就业课 第一阶段】HTML5 零基础到实战(五)基础元素
  5. 无限踩坑系列(4)-远程登入服务器
  6. r语言 悲观剪枝_《R语言编程—基于tidyverse》新书信息汇总
  7. 在中标麒麟上基于源码安装第二个gcc编译器
  8. Vue 制作滚动字幕,用于展示通知内容
  9. Win10s分屏设置
  10. fastapi 参数
  11. HDU 4884 —— TIANKENG’s rice shop(模拟)
  12. 计算机多种形状我来画教案,小学电脑画图——曲线-教案(6页)-原创力文档
  13. python scripts文件夹里面没有pip.exe怎么办?
  14. 真香!JetBrains 推出编程字体 Mono,开源免费可商用
  15. Java导入Excel文件日期解析成了中文问题解决
  16. 拼多多搜索怎么测图测款?教你快速找出店铺内潜在爆款
  17. Qt-ubuntu20.04下+gcc-64编译qt5.15.2的mysql驱动
  18. Modelsim的仿真之路(结束篇之波形比较)
  19. 基于MFC的简易登录器
  20. 如何利用亚马逊关键词进行引流?权威关键词设置技巧来了

热门文章

  1. Mac OS X的快捷键
  2. 【转】文件恢复神器extundelete
  3. github心得体会
  4. Runnable接口和贪心算法
  5. 一、cocos2dx之如何优化内存使用(高级篇)
  6. C++中类的大小问题
  7. 看我是怎样让客户更快找到我的!
  8. 《.Net框架程序设计》读书笔记 之 结构和索引器
  9. rtsp发送主流和辅流
  10. 学籍管理系统 c语言流程图,程序设计基础 ——C语言第10章 综合应用案例——学生学籍管理系统...