集合幂级数与子集卷积

集合幂级数

在 FMT 和 FWT 里有提到过。

对于一个序列 a0aN,定义一个多元多项式 A(x1xn)=0I<2naIx1i1x2i2xnin,其中 i1inI 这个集合的二进制表示。

这个多项式有 2n 项,每一项的系数就是 a。这个 A 叫做集合幂级数。可以类比序列对应到 OGF 上,集合就会对应集合幂级数。

相较于 FMT 和 FWT 处,我们进一步定义集合幂级数的乘法。这是一个比较有用的概念。

简记集合幂级数为 A(x)=aIxI,给定 A(x)=IaIxI,B(x)=JaJxJ,怎么定义 A(x)B(x)

关键在于怎么定义单项式的相乘,也就是 xIxJ 怎么定义。在普通单项式乘法里,xIxJ=xI+J。但是对于集合幂级数,我们有多种定义。

  1. xIxJ=xIJ

  2. xIxJ=xIJ

  3. xIxJ=xIJ

无论对于哪种定义,都满足交换律和结合律。同时,我们发现这三种定义和与、或、异或卷积都有关系。下面我们来看看。

引理:在 xIxJ=xIJ 时,A(x)B(x) 所得的系数刚好是 a,b 的或卷积。

证明

A(x)B(x)=(IaIxI)(JbJxJ)=I,JaIbJxIJ=K(IJ=KaIbJ)xK

同理,把或卷积替换为与卷积、异或卷积,证明都是类似的。

这个引理表明在做集合幂级数乘法时,仍然可以使用卷积快速求得结果。类比多项式乘法用 FFT 快速计算。

子集卷积

假设我们有两个长为 2n 的序列 a,b,定义其子集卷积 c=ab,满足:

cI=JK=I,JK=\emptyaJbK

就是或卷积额外要求其交集为空。也就是要求 J,KI 的划分。

这个问题可以 O(n22n) 求,而且有两种解法。

法一

来个新定义。

{aJ(t)=aJ[|J|=t]bK(t)=bK[|K|=t]

这可以理解为一个拆分,把序列按下标的集合大小分为不同类。

观察到 cI=t=0|I|JK=IaJ(t)bK(|I|t)。因为 JK=IJK=\empty,所以 |J|+|K|=|I|。于是就可以枚举 |J|=t,则有 |K|=|I|t

然后怎么求 c

a(t)b(t) 的或卷积记作 c(t,t)。那么 cI=t+t=|I|cI(t,t)


容易给出一个算法:

  1. 预处理 c(t,t)

  2. 枚举 |I|=i

  3. 枚举 (t,t) 满足 t+t=i

  4. c(t,t) 中大小为 i 的项加入 cI


分析一下复杂度。

第一步预处理,O(n2n2n)。之后统计答案,

还是太慢了,我们再来一个优化:

定义 cI(i)=t+t=icI(t,t)。目标转化为求 cI(0n)

c(i) 怎么求?

c(i)=t+t=ic(t+t)=iDMT(DMT(t+t=ic(t,t)))=iDMT(t+t=iDMT(c(t,t)))=iDMT(t+t=iDMT(c(t,t)))=iDMT(t+t=iDMT(a(t))DMT(b(t)))

:这里的点乘就是向量点乘。

注 2:这里能把 DMT 拿进括号里,是因为它是线性变换。

先预处理 a(x),b(x)DMT 序列,是 O(2nn2n)=O(n22n) 的。

然后 (t+t=iDMT(a(t))DMT(b(t))) 这一部分的点乘是单次 O(2n),总共 O(n2n) 的。

最后对每个 c(i) 各做一次 iDMT,单次 O(n2n),总共 O(n22n)

总复杂度为 O(n22n)

法二

需要用到占位集合幂级数。这个东西也很有用,对集合幂级数的 exp 和 ln 都有用。

下面给出它的定义。

设有一个长度 2n 的序列 aI。定义一个占位集合幂级数 A[z](x1xn)=IaIxIz|I|,普通集合幂级数就是 A[1](x1xn)注意 z 对应的是数字而不是集合。

占位集合幂级数也可以定义乘法:xIzuxJzv=xIJzu+v。对与卷积和异或卷积也是类似的。不过这里要用来解决子集卷积就携程或卷积的形式。

我们定义 xIzu 是合法项,当且仅当 |I|=u。容易发现 I,J 不相交 xIz|I|xJz|J| 为合法项。

简写 A[z](x1xn)A[z]


引理:设 c=ab(子集卷积),aA[z],bB[z],cC[z]。有:A[z]B[z] 保留合法项后恰为 C[z]

证明比较显然。不合法项在子集卷积中是不会出现的。


保留合法项是很容易的,只要 O(2n) 遍历每一项判断即可。那么问题变成求 A[z]B[z]

法 1

A(i)a(i)集合幂级数。这个 a(i) 就是在法一中按集合大小分组的 a(t)B(i) 类似定义。

{A[z]=A(0)+A(1)z++A(n)znB[z]=B(0)+B(1)z++B(n)zn

枚举 i,对于 A[z]B[z]zi 项,包含它的项为 t+t=iA(t)ztB(t)zt=t+t=i(A(t)B(t))zi

而对于 A(t)B(t) 的处理,我们和上面一样进行 iDMT,DMT,利用 DMT 的线性变换性质把集合幂级数的相乘转化为向量的点乘,从而优化复杂度。

具体细节略去。这种方法本质和上面是相同的。不过是引入了 z 作为主元

法 2

此种方法不同,它并非按 z 分类,而是把 z 看作参数

A[z],B[z] 当作普通的集合幂级数,但是每一项的系数不是一个数,而是一个关于 z 的多项式。

具体而言,A[z]=I(aIz|I|)xIB[z]=I(bIz|I|)xI。这里 (aIz|I|)(bIz|I|) 看作系数。

计算 A[z]B[z]=iDMT(DMT(A[z])DMT(B[z])),现在的问题是对于系数是多项式的时候 DMT 是怎么定义的。

其实没有区别,aI=JIaI,不过前缀和变成了多项式的和。子集反演后也是一样。

复杂度呢?

普通数组做 DMTO(n2n) 的,但是现在系数是一个长度为 n 的多项式,所以复杂度是 O(n22n) 的。

A[z],B[z] 各自求 DMT,复杂度 O(n22n);让两个结果点乘,复杂度 O(2n);对点乘的结果再做 iDMT,复杂度 O(n22n)。注意这里 iDMT 的复杂度也是平方,因为 iDMT 也要对多项式运算。

posted @   FLY_lai  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示