集合卷积。
(前置知识 : 准备一份 2015 年国家集训队论文,翻到最后一篇文章。)
例题: CF914G
显然令 f1(S)=fibS∑A∈2U∑B∈2U[A∩B=∅][A∪B=S]cntAcntB,f2(S)=fibScntS,f3(S)=fibS∑A∈2U∑B∈2U[A⊕B=S]cntAcntB,f(S)=∑A∈2U∑B∈2U∑C∈2U[A∩B∩C=S]f1(A)f2(B)f3(C)
其中 A,B,C,S 均为用二进制表示的集合。fibi,cnti 分别表示第 i 项 fibnacci 数和读入中 i 的个数 , 2U 表示所有二进制集合的集合。
则答案 =∑i=016f(2i)
这时,暴力转移是 O(4n) 的 (f1 利用子集枚举法可以优化到 O(n3)).
我们来分别考虑一下每一个函数的优化。
( 注意:部分公式的表示形式和表述方式与论文中不同,请注意区分 )
集合并卷积
(OR Convolution, 参考论文 P273)
首先考虑 hS=∑A∈2U∑B∈2U[A∪B=S]fAgB, 记做 h=f∣g
定义 fS^=∑T⊆SfT(Mobius 变换)
则 hS^=∑A∈2U∑B∈2U[A∪B⊆S]fAgB=∑A⊆S∑B⊆SfAgB=(∑A⊆SfA)(∑B⊆SgB)=fS^gS^
此时计算复杂度变为为 O(2n).
考虑 fS 与 fS^ 的转化(快速 Mobius 变换, FMT):
考虑 gS,i=∑T⊆S,S−T⊆{1,2,…i}f(T), 即 ∀x∈S且x∈[i+1,n],x∈T. 则由定义得 gS,0=fS,gS,n=fS^, 那么我们考虑如何转移。若 i∈S, 对于所有满足条件的 T, 若 i∈T, 则会在 gS,i−1 被计算到, 反之会在 gS−{i},i−1 被计算,所以 gS,i=gS,i−1+gS−{i},i−1, 若 i∈/S, 则只有 gS,i=gS,i−1
同样,也可以利用上面的递推式从 fS^ 反推出 fS。复杂度均为 O(n2n)
另外,根据容斥原理,fS=∑T⊆S(−1)∣S∣−∣T∣fT^。 ( 这个式子在算法中并不需要 )
这样我们就可以用 O(n2n) 的时间求解这个问题。
接下来我们来看例题中第一个子问题。
不相交集合并卷积
(Subset Convolution, 论文 P281)
形式同 f1: hS=∑A∈2U∑B∈2U[A∩B=∅][A∪B=S]fAgB,
可以发现原式的限制可以转化为 ∣A∣+∣B∣=∣S∣,A∪B=S.
后半部分为集合并卷积。则我们只需要再加一维状态记录集合大小。
即设 Fi,S={fS,0,∣S∣=iotherwise
那么原式可以写做 Hi=∑j+k=iFj∣Gk
则 hS=H∣S∣,S
其中枚举 i,j,k 是 O(n2) 的,右侧集合并卷积为 O(2n)(当然要先预处理每一个 Fi 的莫比乌斯变化),所以总复杂度 O(n22n)
集合交卷积
(AND Convolution)
hS=∑L∈2U∑R∈2U[L∩R=S]fLgR, 记做 h=f&g
( 对应原式就是计算 f=f1&f2&f3)
这一部分论文中没有,因为其不满足论文中所限定的 S opt ∅=S(见 P273)(集合交仅满足 S opt U=S, U 为全集)
但是实际上其推导过程与集合并卷积相类似:
设 fS^=∑T⊇SfT
则 fS=∑T⊇S(−1)∣T∣−∣S∣fT^
则 hS^=∑L∈2U∑R∈2U[S⊆L∩R]fLgR=(∑L⊇SfL)(∑R⊇SgR)=fL^gR^
计算 fS^:
( 设 gS,i=∑T⊇S,T−S⊆{1,2,…,i}fT,gS,n=fS^,gS,0=fS)
gS,i={gS,i−1,gS,i−1+gS∪{i},i−1,i∈Si∈/S
复杂度同样为 O(n2n)
集合对称差卷积
(XOR Convolution, 论文 P277)
计算 f3:hS=∑A∈2U∑B∈2U[A⊕B=S]fAgB, 也就是 A,B 的(二进制表示的)异或和等于 S.
首先我们有 ∑T∈2U(−1)∣S∩T∣=[s=∅]2n ( 证明参见论文 )
另外,(−1)∣S∩(A⊕B)∣=(−1)∣S∩A∣+∣S∩B∣, 即二者奇偶性相同,可以通过画图简单验证。
定义 Walsh 变换 fS^=∑T∈2UfT(−1)∣S∩T∣ 及其逆变换 fS=2n1∑T∈2UfT^(−1)∣S∩T∣。
可将 Walsh 变换回代并利用上面的公式来证明逆变换正确性。
然后我们就能得到:
hS^=∑T∈2UhT(−1)∣S∩T∣=∑T∈2U(−1)∣S∩T∣∑A∈2U∑B∈2U[A⊕B=T]fAgB=∑A∈2U∑B∈2UfAgB(−1)∣S∩(A⊕B)∣=∑A∈2U∑B∈2UfAgB(−1)∣S∩A∣+∣S∩B∣=(∑A∈2UfA(−1)∣S∩A∣)(∑B∈2UgB(−1)∣S∩B∣)=fS^gS^
然后考虑如何进行 Walsh 变换(逆变换只需要除以 2n 或乘上其逆元)
和前面同样的思路,设 gS,i=∑T∈2U,T⊕S⊆{1,2,…,i}fT(−1)∣S∩T∣,gS,n=fS^,gS,0=fS)
则当 i∈/S 时, gS,i=gS∩{i},i−1(i∈T)+gS,i−1(i∈/T);
当 i∈S 时, gS,i=gS−{i},i−1(i∈/T)−gS,i−1(i∈T).
如果不理解负号原因(至少我一开始是如此), 可以参考Wikipedia 上 的这张图片。下面给出我的理解。
考虑到最终状态,∑T∈2UfT(−1)∣S∩T∣, 则我们分解 (−1)∣S∩T∣, 就会发现相当于是当 i∈S且i∈T 时将答案 ×(-1)。
而从另一个角度来看,我们考虑如果根据 gS,i 的定义 ,gS,0 应该为 fS(−1)∣S∣, 而实际上的初始值为 fS, 则此时就会对答案造成影响。而 Walsh 变换就可以通过这一正负号弥补这一影响。
另外,可以将 fS 看作 n 维数组 fa1,a2,⋯,an,ai∈{0,1}, 根据卷积定理(可以参考 WC2018 营员交流),则可以对每一维分别进行一次变换。我们采用 DFT 作为变换,则也可以推出上述式子。
那么我们也能在 O(n2n) 时间内解决这个问题。
那么现在我们已经解决这道题目了, 总复杂度 O(n22n)。
在具体代码实现上,可以(也普遍)采用滚动数组,而且这些转移都是独立的,所以在转移时并不需要刻意改变枚举顺序。
–THE END–