详细揭秘:集合划分容斥的容斥系数

dp 转移时,我们有时会要求枚举一个极大的合法子集进行转移,但是往往不能很好地处理极大的限制,只能枚举一个不作限制的合法子集。我们希望通过容斥使得每个极大的子集的转移正确。

引用一份看到的形式化描述:在某种等价关系下,对于某一组合结构,构成其的元素其可以被划分成若干等价类,有一关于等价类的系数 F(x)(即这一等价类的贡献系数)。而我们的 dp 不能恰好地刻画出每一极大等价类(有可能有相互等价的等价类),记等价类之间的合并关系为 G(x),我们设计容斥系数 H(x) 满足:

G(H(x))=F(x)

例:DAG 定向问题

给你一个 n 个点 m 条边的无向图,给每条边定向并要求不出现环,求定向方案数。

n18

我们知道,这个经典问题的 dp 方法为每一次枚举当前入度为 0极大子集 T 将其删去。设 gS 表示 S 内的点能否入度为 0,即 S 是否是独立集,fS 表示 S 内点的定向方案,有:

fS=TSfS/TgT(1)|T|1

我们尝试用上述方法得到这个 (1)|T|1 的容斥系数:[xS]F(x) 表示的是极大的入度为 0 的点集为 S 时需要贡献的系数,显然 [xS]F(x)=[S]。合并方式为每次加入一个非空无交子集,可以得出 G(x)=11x1。所以 11H(x)=F(x)+1,手动求逆得到 [xS]H(x)=(1)|S|1

A(x)=SgS(1)|S|1xS,所求即为 [xU]11A(x)

例:计树

求有多少不同的包含 n 个点的有标号无根树,满足:对于任何一个点 x,都存在点 y 使得 xy 之间有一条边且 |xy|=1

n105

树的形态必定为若干值域连续的链拼起来。

根据 Prufer 定理,k 个大小分别为 w1k 的连通块形成树的方案数为:

nk2wi

那么我们每加入一条极长的长为 w(w2) 的链将答案乘以 nw,最后除以 n2。因为我们不能钦定极长,所以需要容斥。

题目要求链长 2,那么 F(x)=i2xi=x21x;合并方式与 DAG 定向问题类似,每次直接拼一段上去,G(x)=11x1;简单计算得到 H(x)=x21x+x2

A(x)=wwnxw[xw]H(x),所求即为 [xn]11A(x)

例:Yet Another ABC String

给出 a,b,c,求由 a 个 A,b 个 B,c 个 C 构成的字符串数量,使得不存在子串 ABCBCACAB

a,b,c106

将序列划分为若干极长的形如 ..BCABC...AB... 的连续段。则每个连续段必须 2F(x)=x+x2H(x)=111+x+x2

手玩求逆可以得到:

[xi]H(x)={1i0(mod3)1i1(mod3)0i2(mod3)

A(x,y,z) 为一个连续段的生成函数:

A(x,y,z)=3i1(xyz)i+(x+y+z)i0(xyz)i=x+y+z3xyz1xyz

答案为:

[xaybzc]11A(x,y,z)

[xaybzc]1xyz1xyz+2xyz

i0(2)i[(a+b+c2iai,bi,ci,i)(a+b+c2i3ai1,bi1,ci1,i)]

例:Yet Another Permutation Problem

有一个长为 n 的排列 p,初始 pi=i,接下来你需要对它进行若干次操作,每次操作你可以指定一个 x[1,n],将 px 取出后放在排列的开头或末尾。对 k[0,n) 求出经过 k 次操作能得到几种不同的排列。

n1000

判断一个排列是否可行,考虑将操作反过来:将排列的开头或末尾任意插入排列中。不难发现排列合法当且仅当存在一个长度 nk 的上升子区间,将该区间外的数依次向内插入即可。

m=nk,不妨计数所有极长上升子区间长度都 <m 的排列数量。F(x)=xxm1xH(x)=xxm1xm

A(x) 为一个上升子区间的 EGF,即 A(x)=i[xi]H(x)xii!,所求即为 n![xn]11A(x)。注意到 A(x) 只有 O(nm) 项,所以直接暴力求逆也可做到 O(n2logn)

例:Distinct Multiples

给定 n,m 以及一个长为 n 的序列 d1n,你需要计数有多少个值域为 [1,m] 的序列 a1n 满足 di|aiai 两两不同。

n16

考虑令等价类为相等的数的集合,则所有极大等价类大小必须都为 1,即 [xS]F(x)=[|S|=1]。注意此处等价类之间的合并是无序的,则 G(x)=expx1H(x)=ln(F(x)+1),模拟得 [xS]H(x)=(1)|S|1(|S|1)!

fS 表示等价类 S 的方案数,A(x)=SfS(1)|S|1(|S|1)!xS,所求即为 [xU]expA(x)

例:A Nameless Counting Problem

给定 n,m,x,求有多少个长为 n 的单调不降序列 a1n,满足 an<mxori=1nai=x

n200

考虑不断将序列中相同的数配对删除,最终得到一个单增的序列。一个长为 k 的不重序列对应回原序列的方案数为 [kn(mod2)]1k!(m+(nk)/2(nk)/2)

容斥掉互不相同的限制,容斥系数同上题。但此时答案不能简单地由状态的等价类信息得出。设 fi,j,d 表示长为 i 的序列,由高至低考虑到第 d 位,有 j 个数顶着上界 m 时满足 x 这些位的限制的方案数,转移可以枚举这一位有几个数仍顶着上界。

考虑分别有 i,j 个奇偶大小的等价类,则贡献为 mjfi,0,0,则设 gi,j 为目前已经有 i 个数,有 j 个奇数大小等价类的贡献和。等价类之间无序,转移时枚举包含 1 的等价类大小即可。

时间复杂度 O(n3logv),使用生成函数刻画可以得到更优的做法。

例:异或图

给定一个 n 个点 m 条边的图以及一个长为 n 的序列 a1n,有一常数 C,你需要求出有多少序列 b1n 满足 0biai(u,v)E,bubvxori=1nbi=C

n15

考虑 m=0 怎么做,从高至低枚举第一个不全顶到上界的位 d,则低 d1 位只需要一个在第 d 位不顶到上界的数进行调整,其余数任选即可。

令等价类为相等的数的集合,则 [xS]F(x) 等于 1 当且仅当 S 内点在图上为独立集。H(x)=ln(F(x)+1) 可以直接求出。

考虑一个状态的答案,我们只关注每个等价类内部的最小值。每个大小为偶数的等价类均可随便取,大小为奇数的等价类的最小值(称为关键点)构成 m=0 的子问题。

fS,T 表示当前已经考虑了 S 内的点,其中关键点的集合为 T 的方案数,时间复杂度为 O(4n)

此时记录了大量无用信息,我们将 a 从小到大排序,逐个尝试加入关键点。设当前加入到 i,则 [1,i) 的点已经必然在考虑的点集中,只需要记录它们是否在关键点集中;[i,n] 的点必然不在当前关键点集中,只需要记录它们是否在已考虑点集中。这样状态数就减小至 2n,再加上枚举子集,时间复杂度为 O(3nn+2n(m+nlogV))

posted @   ffffyc  阅读(130)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示