集合并卷积的三种求法(分治乘法,快速莫比乌斯变换(FMT),快速沃尔什变换(FWT))
本文主要内容是对武汉市第二中学吕凯风同学的论文《集合幂级数的性质与应用及其快速算法》的理解
定义
集合幂级数
为了更方便的研究集合的卷积,引入集合幂级数的概念
集合幂级数也是形式幂级数的一种,只是集合的一种表现形式,无需考虑收敛或发散的含义
定义一个集合 \(S\) 的集合幂级数为 \(f\) ,那么我们就可以把集合 \(S\) 表示为如下形式
\(\begin{aligned}f=\sum _{T\subseteq S}f_{T}\cdot x^{T}\end{aligned}\)
\(f_T\)为\(T\)这个集合幂级数的系数
简单来说就是用二进制表示集合的元素是否存在,并将其写成多项式的形式
约定
\(c=\left(a,b\right)\)表示将\(a,b\)连起来组成\(c\)
为了方便,将\(f*g\)写成\(fg\)
卷积运算
加法
\(\begin{aligned}h=f+g\end{aligned}\)
那么
\(h_S=f_S+g_S\)
减法
\(\begin{aligned}h=f-g\end{aligned}\)
那么
\(h_S=f_S-g_S\)
乘法
\(\begin{aligned}h=f*g\end{aligned}\)
那么
\(\begin{aligned}h_S=\sum_{i∘j\subseteq S}f_i\times g_j\end{aligned}\)
其中\(∘\)可以是与,或,异或运算
集合并卷积 就是\(∘\)进行或运算
子集卷积 就是\(∘\)进行与运算
集合对称差卷积 就是\(∘\)进行异或运算
快速求法
加法和减法都可以在\(O(n)\)时间复杂度内求出结果
对乘法,有一些优化的算法,以集合并卷积为例
分治
设\(f\)有\(2^n\)项
考虑将其集合幂级数的第\(n\)个元素提出来
则\(f=f^-+x^{\{n\}}f^+\),可以知道\(f^-\)为前\(2^{n-1}\)项,\(f^+\)为后\(2^{n-1}\)项即\(f^-\)的第\(n\)个元素在二进制下为\(0\),\(f^+\)的第\(n\)个元素在二进制下为\(1\)
\(\begin{aligned}fg&=\left( f^-+x^{\{n\}}f^{+}\right) \left( g^{-}+x^{\{n\}}g^{+}\right)\\
&=f^-g^-+x^{\{n\}}\left( f^-g^{+}+f^{+}g^-+f^{+}g^{+}\right) \\
&=f^-g^-+x^{\{n\}}\left(\left(f^-+f^+\right)\left(g^-+g^+\right)-f^-g^-\right)
\end{aligned}\)
这样计算\(fg\)就只要计算\(f^-g^-\)和\(\left(f^-+f^+\right)\left(g^-+g^+\right)\)了
此时已经没有\(n\)这个元素了
于是我们可以递归分治求解\(fg\)
时间复杂度\(O\left(n2^n\right)\)
\(\mathcal{Code}\)
void fold (int *f,int *g,int *h,int hlen)//hlen -> half len
{
if (hlen==1) return void(h[0]=f[0]*g[0]);
for (int i=0;i<hlen;++i) f[i+hlen]+=f[i],g[i+hlen]+=g[i];
fold(f,g,h,hlen>>1),fold(g+hlen,g+hlen,h+hlen,hlen>>1);
for (int i=0;i<hlen;++i) f[i+hlen]-=f[i],g[i+hlen]-=g[i];
}
快速莫比乌斯变换(FMT)
对于一个集合幂级数\(f\),我们定义其快速莫比乌斯变换为集合幂级数\(\widehat f\),使其系数满足
\(\begin{aligned}\widehat f_S=\sum_{T\subseteq S}f_{T}\end{aligned}\)
由容斥原理,我们可以得到
\(\begin{aligned}f_S=\sum_{T\subseteq S}\left(-1\right)^{|S|-|T|}\widehat f_T\end{aligned}\)
考虑乘法\(\widehat h=\widehat f\widehat g\)
\(\begin{aligned}\widehat h_{s}&=\sum _{i\subseteq S}\sum _{j\subseteq S}f_{i}g_{j}\\
&=\left(\sum _{i\subseteq S}f_i\right)\left(\sum _{j\subseteq S}g_{j}\right)\\
&=\widehat f_S \widehat g_S
\end{aligned}\)
那么,现在我们知道想办法怎么求\(\widehat f\)和\(\widehat g\),然后把它们的系数乘起来,就可以得到\(\widehat h\)
然后再将其反演得到\(f\)(因为容斥是肯定会超时的)
考虑递推
我们设\(\widehat f_S^{\left(i\right)}\)使其满足
\(\begin{aligned}\widehat f_S^{\left(i\right)}=\sum _{T\subseteq S}\left[ \left( S-T\right) \subseteq \left\{ 1,2,\ldots ,i\right\} \right] f_{T}\end{aligned}\)
即若\(i+1\sim n\)有元素属于\(S\),则必须要选择,而\(1\sim i\)中的元素可有可无
那么我们最终的\(\widehat f_S=\widehat f_S^{\left(n\right)}\),所有的元素都是可有可无的,即它的子集都被包含在内了
考虑第\(S\)中有没有\(i\)这个元素
- 没有,则\(\widehat f_S^{\left(i\right)}=\widehat f_S^{\left(i-1\right)}\)
- 有,那么\(\widehat f^{\left( i\right) }_{S}=\widehat f^{\left( i-1\right) }_{S}+\widehat f^{\left( i-1\right) }_{S- i}\),\(S-i\)表示从\(S\)这个集合中去掉\(i\)这个元素,这个式子的后两项前者是第\(i\)个元素一定被选了,后者则是第\(i\)个元素一定没有被选
而要将其反演,我们考虑其逆过程,只需将所有加上来的全部减去即可
时间复杂度\(O\left(n2^n\right)\)
\(\mathcal{Code}\)
上面做法都是二维数组
考虑先枚举\(i\)再算所有\(S\)的答案,只需一维数组即可
void FMT (int *a,int n)//n个元素
{
int all=1<<n;
for (int i=0;i<n;++i)
for (int j=0;j<all;++j)
if (j>>i&1) a[j]+=a[j^(1<<i)];
}
void IFMT (int *a,int n)//n个元素
{
int all=1<<n;
for (int i=0;i<n;++i)
for (int j=0;j<all;++j)
if (j>>i&1) a[j]-=a[j^(1<<i)];
}
快速沃尔什变换(FWT)
我们发现,在进行分治算法中,只需保留出\(f^-,g^-\),\(\left(f^-+f^+\right),\left(g^-+g^+\right)\)就可以算出答案了
可惜递归的常数相对来说太大,我们考虑将其写成循环的形式就可以得到\(FWT\)了
若不考虑分治写成循环,我们换一种方法理解\(FWT\),当然,这是另一种思路了,上面将递归改成循环的思路是正确的
上面的\(f=f^-+f^+\),我们是始终让其满足这个条件的,所以在后面还减去了一个\(f^-g^-\)
让我们跳出思维的局限,弄这么一个\(f',g'\)使其满足\((fg)'=f'g'\),这样我们只要计算\(f'g'\),然后把它反演一下就可以得到\(fg\)
这里呢
\(f'=\left(f^-,f^-+f^+\right)\)
为什么这样就可以呢
考虑\((fg)'\),根据上面的推导
\(\left(fg\right)'=\left(f^-g^-,\left(f^-+f^+\right)\left(g^-+g^+\right)\right)\)
再考虑\(f'g'\)
\(f'^-g'^-=f^-g^-\)
\(f'^+g'^+=\left(f^-+f^+\right)\left(g^-+g^+\right)\)
所以这样是可以的
于是我们可以得到
\(f'=\left(f^-,f^-+f^+\right)\)
然后称这样的\(f'\)叫做沃尔什变换
\(FWT\left(f\right)=FWT\left(f^-,f^-+f^+\right)\)
反演也很简单
即将多算的\(f^-\)减去即可
\(\mathcal{Code}\)
void FWT (int *a,int n)
{
for (int len=2;len<=n;len<<=1)
for (int i=0,hlen=len>>1;i<n;i+=len)
for (int j=i,k=j+hlen;j<k;++j)
a[j+hlen]+=a[j];
}
void IFWT (int *a,int n)
{
for (int len=2;len<=n;len<<=1)
for (int i=0,hlen=len>>1;i<n;i+=len)
for (int j=i,k=j+hlen;j<k;++j)
a[j+hlen]-=a[j];
}
时间复杂度\(O\left(n2^n\right)\)
如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧
如能得到推荐博主就更开心了
您的鼓励是博主的动力
集合并卷积的三种求法(分治乘法,快速莫比乌斯变换(FMT),快速沃尔什变换(FWT))的更多相关文章
- 卷积的三种模式:full, same, valid
通常用外部api进行卷积的时候,会面临mode选择. 本文清晰展示三种模式的不同之处,其实这三种不同模式是对卷积核移动范围的不同限制. 设 image的大小是7x7,filter的大小是3x3 1,f ...
- 卷积的三种模式:full、same、valid + 卷积输出size的计算
转自https://blog.csdn.net/u012370185/article/details/95238828 通常用外部api进行卷积的时候,会面临mode选择. 这三种mode的不同点:对 ...
- java 集合之HashMap的三种遍历
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射. 这周我们只需记住三种遍历方法 1.通过keySet()获取键,再利用hashmap里面的.get(key)方法通过键获取 ...
- [OI笔记]三种逆元的求法
其实这篇博客只是搬运一下我之前(大概是NOIP那会)写在word里的笔记- 下面直接复制原话,题目是洛谷上求逆元的模板题:https://www.luogu.org/problemnew/show/P ...
- 【Java EE 学习 28 上】【oracle学习第二天】【子查询】【集合运算】【几种数据库对象】
一.子查询 1.为什么要使用子查询:问题不能一步求解或者一个查询不能通过一步查询得到. 2.分类:单行子查询和多行子查询. 3.子查询的本质:一个查询中包含了另外一个或者多个查询. 4.使用子查询的规 ...
- LCS的几种求法
\(LCS:\) 对于两个长度均为 \(N\) 的数列 \(A\) 和 \(B\) ,存在一个数列 \(C\) 使得 \(C\) 既是 \(A\) 的子序列有事 \(B\) 的子序列,现在需要求这个数 ...
- Java使用三种不同循环结构对1+2+3+...+100 求和
▷//第一种求法,使用while结构 /** * @author 9527 * @since 19/6/20 */ public class Gaosi { public static void ma ...
- UOJ272 [清华集训2016] 石家庄的工人阶级队伍比较坚强 【分治乘法】
题目分析: 首先不难注意到式子就是异或卷积,所以考虑用分治乘法推出优化方法.我们把一个整体$f$拆成$f-,f\pm,f+$,然后另一个拆成$g-,g\pm,g+$.这样做的好处是能更清楚的分析问题. ...
- java中遍历集合的三种方式
第一种遍历集合的方式:将集合变为数组 package com.lw.List; import java.util.ArrayList; import java.util.List; import ja ...
随机推荐
- laravel修改了配置文件不生效,修改了数据库配置文件不生效
Laravel缓存配置文件,因此您可能只需要清除缓存: php artisan config:clear 转: http://www.voidcn.com/article/p-sgcusrjp-bxw ...
- CopyOnWrite 思想在 Kafka 源码中的运用
CopyOnWrite 思想在 Kafka 源码中的运用 在 Kafka 的内核源码中,有这么一个场景,客户端在向 Kafka 写数据的时候,会把消息先写入客户端本地的内存缓冲,然后在内存缓冲里形成一 ...
- Swagger 慢
Swagger 慢 - 国内版 Binghttps://cn.bing.com/search?FORM=U227DF&PC=U227&q=Swagger+%E6%85%A2 rest框 ...
- Python带参数的函数装饰器
# -*- coding: utf-8 -*- # author:baoshan # 带参数的函数装饰器 def say_hello(country): def wrapper(func): def ...
- Influxdb修改数据保留策略
retention policy: 存储策略,用于设置数据保留的时间,每个数据库刚开始会自动创建一个默认的存储策略 autogen,数据保留时间为永久,之后用户可以自己设置,例如保留最近2小时的数据. ...
- 将一个多表关联的条件查询中的多表通过 create select 转化成一张单表的sql、改为会话级别临时表 【我】
将一个多表关联的条件查询中的多表通过 create select 转化成一张单表的sql 将结果改为创建一个会话级别的临时表: -- 根据下面这两个sql CREATE TABLE revenu ...
- System.InvalidOperationException:“No coercion operator is defined between types 'System.Int16' and 'System.Boolean'.”
modelBuilder.Entity<MentItems>().Property(e=>e.IsValid) .HasColumnType("bit(1)") ...
- 软件定义网络基础---OF-Config协议
交换机与控制器继续通信前,是需要对其功能.特性以及资源进行配置才能进行工作,这些配置是如何实现的?是由专门的配置协议指导完成的 一:OF-Config协议 是OpenFlow交换机管理配置协议,是Op ...
- 算法习题---5-7打印队列(UVa12100)
一:题目 有一个打印机,有一些任务在排着队打印,每个任务都有优先级.打印时,每次取出队列第一个任务,如果它的优先级不是当前队列中最高的,就会被放到队尾,否则就打印出来.输出初始队列的第m个任务的打印时 ...
- PP篇7 生产替代料齐套后处理
扫描可关注本人技术分享公众号,与您一起学习新知! 对于计划订单和生产订单, 当存在替代料的时候,完成齐套性检查后,按照可齐套量进行拆单,并删除不能齐套的替代料(有个删除规则).不能齐套就按照优先级最高 ...