§1. 等价容斥
(乱取的名字.)
题目将组合对象构成的 "等价类" 进行了定义和限定. 我们往往无法计数 "等价类真的长这样" 的方案, 而只能求出 "钦定等价类长这样, 但不能保证等价类间不等价" 的方案. 这个时候就可以用「等价容斥」求出最终答案.
形式化地, 设题目要求每种等价类对答案的贡献系数构成关于等价类大小的 GF C(x), 那么我们设单个等价类的容斥系数为 G(x), 多个被钦定的等价类的合并规则遵从表达式 f(G), 并希望它们满足
C(x)=f(G(x)).
这里 f 通常比较简单, 于是能找到 G 的简介表达. 之后在钦定等价类时, 为大小为 k 的等价类带上 [xk]G(x) 的容斥系数, 组合时容斥系数求乘积, 就能得到最终的答案.
如果继续扯下去真的玄虚之至了, 我们来看点具体的例子.
Example 1.1. 「洛谷 P7275」计数 Link & Submission.
Solution. 考虑一棵合法的树, 其必然能被唯一地剖分为若干条长度 >1 的树链, 每条树链的结点编号对应一个区间. 反过来, 我们可以先将 [1,n] 划分为若干区间, 再用边将它们连起来, 同时保证不会让两个区间合并.
"不会合并" 这个限制比较麻烦, 先把它扔掉, 此后连接区间的方案数可以用 Prufer 算. 令 f(i,j) 表示把 [1,i] 划分为长度为 l1..j 共 j 段时 nj∏klk 之和. 考虑等价容斥, 令 [xl]G(x) 表示长为 l 的区间的容斥系数, 那么 l 的容斥系数总贡献为
cl=[xl]∑i≥1Gi(x)=[xl](11−G(x)−1).
我们希望 cl=[l>1], 于是
11−G(x)−1=x21−x⇒G(x)=x2x2−x+1.
手算一下系数, 发现
SEQG(x)=⟨0,0⟩⟨1,1,0,−1,−1,0⟩+∞.
于是, 单个区间的 OGF H(x) 为
H(x)=∑ini⋅[xi]G(x).
欲求的 f(n,i) 为
f(n,i)=[xn]Hi(x).
最后
ans=n−2∑i[xn]Hi(x)=n−2[xn]11−H(x).
直接多项式可以做到 O(nlogn). 当然可以发现这是个线性递推求远项, 所以也能 O(logn).
Example 1.2. jiangly 的排列数数题 给定 n, 对于每个 k, 求有多少个 n 阶排列含有至少一个长度为 k 的上升段. 也许 n≤2×103?
Solution. 容斥成 "不含". 固定 k, 令 Gk(x) 为容斥系数, 与上题类似地有
11−Gk(x)−1=x−xk1−x⇒Gk(x)=1−x1−xk.
答案:
ans=n![xn]11−∑igi/i!⋅xi.
注意 Gk(x) 只有 O(n/k) 项, 暴力求逆 O(n2/k), 总共 O(n2logn). EI 提出了更厉害的优化.
Example 1.3. 「LOJ #6728」U 群把妹王 Link & Submission.
Solution. 来容斥. 令 R(x) 表示行上容斥系数的 EGF, 那么
expR(x)−1=∑i∈Sxii!⇒R(x)=ln(1+∑i∈Sxii!).
选行, 令 fi=[xi]F(x) 表示把 n 行钦定为 i 个等价类 (等价类间可能存在等价关系) 的方案数, 那么
fi=n!i![xn]Ri(x).
选列, C(x),gi=[xi]G(x) 类似. 最终答案为
ans=∑i,jfigjkij=∑i,jfigjk(i+j2)−(i2)−(j2).
答案倒是好算, 问题是 f,g 比较麻烦. 注意到
F(z)=n![xn]expzR(x).
(注意 F(z) 是 OGF 而非 EGF.) 因为 |S| 较小, 所以牛迭可以 O(|S|nlogn) 求出 R(x) 的复合逆 P(x). 大概是解这么一个方程:
p(u,x)=x−ln(1+∑i∈Suii!)=0,u2n≡un−p(un,x)pu(un,x)≡un+(x−lnS(un))S(un)S′(un)(modx2n).
最后套拉反:
[xn]expzR(x)=1n[xn−1]zezx(xP(x))n.
多项式瞎算即可. O(anlogn+bmlogm), 常数巨大.
§2. 反射容斥
(名字是别人取的.)
双限制的走折线问题. 即求从 (0,0) 走到 (n,m), 每步位移为 (1,±1), 且不能碰到 l1:y=a 和 l2:y=b (a<0<b) 的方案数.
我会做只有 l:y=b! 答案是 [(0,0)→(n,m)]−[(0,0)→(n,2b−m)]. 这里只对第一次碰到 l 的地方进行了 "反射".
现在有 l1,l2, 给出结论, 合法方案数为: 「总方案」−「撞 l1 的方案」−「撞 l2 的方案」+「撞 l1l2 的方案」+「撞 l2l1 的方案」−「撞 l1l2l1 的方案」−「撞 l2l1l2 的方案」+⋯ 注意 "撞" 是指第一次迎面撞上 ("撞上" 前在合法位置).
如何计数呢? 以「撞 l1l2l1l2 的方案」为例, 类似于 l:y=b 的情况, 我们将终点 (n,m) 依次沿 l2,l1,l2,l1 翻折到 P, 计算方案 (0,0)→P. 注意我们容斥的是撞击点的一段后缀, 所以对于任意非空撞击序列, 其从 l1 开始翻和从 l2 开始翻必然会被 ±1 共计数次, 实际上刚好就是 −1. 所以这个容斥很正确. 最后我们就只需要计算 O(n/(|a|+|b|)) 个组合数.
组合意义会引起不安吗 ... 那我们来欣赏一下代数推导. 这里先固定 l1:y=−1, 也就是经典的 Catalan 数形式. 考虑数轴上的行走, 每步位移为 ±1. 记从 0 走到 t 步到 x, 中途不经过 −1 的方案数为 qx,t. 我们知道谜底, 但看破不说破.
考虑暴力地把问题塞进 GF 这个袋子里, 令 Q(x,t)=∑qx,txitj. 容易列出方程
Q(x,t)=1+(x+x−1)tQ(x,t)−x−1tQ(0,t).
整理一下:
(1−(x+x−1)t)⋅xQ(x,t)=x−tQ(0,t).
代入 x←x−1:
(1−(x+x−1)t)⋅x−1Q(x−1,t)=x−1−tQ(0,t).
上下作差:
xQ(x,t)−x−1Q(x−1,t)=x−x−11−(x+x−1)t.
观察系数位置, 可知
Q(x,t)=1−x−21−(x+x−1)t−R(x),
其中 R(x) 的系数仅出现与负指标, 提取 Q(x,t) 的非负指标位置系数时可忽略. 考察提取过程
[xntm]1−x21−(x+x−1)t=[xn](1−x2)(x+x−1)m=[n≡m(mod2)]((mn+m2)−(mn+m2+1)).
我尝试用类似方法推导双限制的反射容斥, 败北了. 可能还是得使用 EI 败北后的反击方法.
Example 2.1. 「UOJ #424」count Link.
Solution. 只需要讨论 n≥m 的情况. 我们可以通过多叉笛卡尔树唯一确定 f. 众所周知, 设树 T 的树根为 r, 其儿子 u1..k, 那么我们存在 T↦S∈{(,)}2(|T|−1) 的单射. 即构造
SEQ(r)=(SEQ(u1))(SEQ(u2))⋯.
所以只需要对这样的序列计数.
如何保证仅仅使用 [1,m] 中的整数? 显然就是要求树高 (叶子到根进过的最多边数) 不超过 m. 对应到括号序列上, 也就是前缀 ( − 前缀 ) 恒 ≤m, 当然这个差值也应该恒 ≥0. 令 l1:y=−1,l2:y=m+1, 我们就得到了标准的反射容斥问题. 当然你可以用 GF, 不过容易败北.
Example 2.2. 求含 n 个 1, m 个 0 的序列, 使得任意区间包含 01 个数差不超过 k. n,m,k≤5×107.
Solution. 从 (0,0) 走到 (n+m,n−m), 任意两点高度差不超过 k. 实际上只需要最高点与最低点高度差不超过 k. 枚举最低高度 a, 容斥求出最低恰为 a, 最高不超过 k−a 的方案数, 这一步是 O((n+m)/k) 的. a 只有 k 种, 所以复杂度 O(n+m).
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2021-07-16 Solution -「多校联训」Sample
2021-07-16 Solution -「多校联训」光影交错