• 集合并卷积的三种求法(分治乘法,快速莫比乌斯变换(FMT),快速沃尔什变换(FWT))


    也许更好的阅读体验

    本文主要内容是对武汉市第二中学吕凯风同学的论文《集合幂级数的性质与应用及其快速算法》的理解

    定义

    集合幂级数

    为了更方便的研究集合的卷积,引入集合幂级数的概念
    集合幂级数也是形式幂级数的一种,只是集合的一种表现形式,无需考虑收敛或发散的含义

    定义一个集合 (S) 的集合幂级数为 (f) ,那么我们就可以把集合 (S) 表示为如下形式

    (egin{aligned}f=sum _{Tsubseteq S}f_{T}cdot x^{T}end{aligned})
    (f_T)(T)这个集合幂级数的系数
    简单来说就是用二进制表示集合的元素是否存在,并将其写成多项式的形式

    约定

    (c=left(a,b ight))表示将(a,b)连起来组成(c)
    为了方便,将(f*g)写成(fg)

    卷积运算

    加法

    (egin{aligned}h=f+gend{aligned})
    那么
    (h_S=f_S+g_S)

    减法

    (egin{aligned}h=f-gend{aligned})
    那么
    (h_S=f_S-g_S)

    乘法

    (egin{aligned}h=f*gend{aligned})
    那么
    (egin{aligned}h_S=sum_{i∘jsubseteq S}f_i imes g_jend{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)
    (egin{aligned}fg&=left( f^-+x^{{n}}f^{+} ight) left( g^{-}+x^{{n}}g^{+} ight)\ &=f^-g^-+x^{{n}}left( f^-g^{+}+f^{+}g^-+f^{+}g^{+} ight) \ &=f^-g^-+x^{{n}}left(left(f^-+f^+ ight)left(g^-+g^+ ight)-f^-g^- ight) end{aligned})
    这样计算(fg)就只要计算(f^-g^-)(left(f^-+f^+ ight)left(g^-+g^+ ight))
    此时已经没有(n)这个元素了
    于是我们可以递归分治求解(fg)
    时间复杂度(Oleft(n2^n ight))

    (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),使其系数满足
    (egin{aligned}widehat f_S=sum_{Tsubseteq S}f_{T}end{aligned})

    由容斥原理,我们可以得到
    (egin{aligned}f_S=sum_{Tsubseteq S}left(-1 ight)^{|S|-|T|}widehat f_Tend{aligned})

    考虑乘法(widehat h=widehat fwidehat g)
    (egin{aligned}widehat h_{s}&=sum _{isubseteq S}sum _{jsubseteq S}f_{i}g_{j}\ &=left(sum _{isubseteq S}f_i ight)left(sum _{jsubseteq S}g_{j} ight)\ &=widehat f_S widehat g_S end{aligned})

    那么,现在我们知道想办法怎么求(widehat f)(widehat g),然后把它们的系数乘起来,就可以得到(widehat h)
    然后再将其反演得到(f)(因为容斥是肯定会超时的)

    考虑递推
    我们设(widehat f_S^{left(i ight)})使其满足
    (egin{aligned}widehat f_S^{left(i ight)}=sum _{Tsubseteq S}left[ left( S-T ight) subseteq left{ 1,2,ldots ,i ight} ight] f_{T}end{aligned})
    即若(i+1sim n)有元素属于(S),则必须要选择,而(1sim i)中的元素可有可无
    那么我们最终的(widehat f_S=widehat f_S^{left(n ight)}),所有的元素都是可有可无的,即它的子集都被包含在内了
    考虑第(S)中有没有(i)这个元素

    • 没有,则(widehat f_S^{left(i ight)}=widehat f_S^{left(i-1 ight)})
    • 有,那么(widehat f^{left( i ight) }_{S}=widehat f^{left( i-1 ight) }_{S}+widehat f^{left( i-1 ight) }_{S- i})(S-i)表示从(S)这个集合中去掉(i)这个元素,这个式子的后两项前者是第(i)个元素一定被选了,后者则是第(i)个元素一定没有被选

    而要将其反演,我们考虑其逆过程,只需将所有加上来的全部减去即可

    时间复杂度(Oleft(n2^n ight))

    (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^+ ight),left(g^-+g^+ ight))就可以算出答案了
    可惜递归的常数相对来说太大,我们考虑将其写成循环的形式就可以得到(FWT)

    若不考虑分治写成循环,我们换一种方法理解(FWT),当然,这是另一种思路了,上面将递归改成循环的思路是正确的
    上面的(f=f^-+f^+),我们是始终让其满足这个条件的,所以在后面还减去了一个(f^-g^-)
    让我们跳出思维的局限,弄这么一个(f',g')使其满足((fg)'=f'g'),这样我们只要计算(f'g'),然后把它反演一下就可以得到(fg)
    这里呢
    (f'=left(f^-,f^-+f^+ ight))
    为什么这样就可以呢
    考虑((fg)'),根据上面的推导
    (left(fg ight)'=left(f^-g^-,left(f^-+f^+ ight)left(g^-+g^+ ight) ight))
    再考虑(f'g')
    (f'^-g'^-=f^-g^-)
    (f'^+g'^+=left(f^-+f^+ ight)left(g^-+g^+ ight))

    所以这样是可以的
    于是我们可以得到
    (f'=left(f^-,f^-+f^+ ight))
    然后称这样的(f')叫做沃尔什变换
    (FWTleft(f ight)=FWTleft(f^-,f^-+f^+ ight))

    反演也很简单
    即将多算的(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];
    }
    

    时间复杂度(Oleft(n2^n ight))

    如有哪里讲得不是很明白或是有错误,欢迎指正
    如您喜欢的话不妨点个赞收藏一下吧
    如能得到推荐博主就更开心了
    您的鼓励是博主的动力

  • 相关阅读:
    dev中gridcontrol为列添加RepositoryItemImageComboBox内置器
    arcengine查询
    利用反射动态创建对象
    arcengine加载模板时实现比例尺与地图的同步
    ArcEngine HRESULT:0x80040215的解决方法( 转)
    Silverlight中的数据访问
    HyperLink链接到项目中的文件
    Silverlight中的数据绑定4
    自定义控件的构建(3)
    自定义控件的构建(1)
  • 原文地址:https://www.cnblogs.com/Morning-Glory/p/11332909.html
Copyright © 2020-2023  润新知