Note - 两类容斥
\(\S1.\) 等价容斥
(乱取的名字.)
题目将组合对象构成的 "等价类" 进行了定义和限定. 我们往往无法计数 "等价类真的长这样" 的方案, 而只能求出 "钦定等价类长这样, 但不能保证等价类间不等价" 的方案. 这个时候就可以用「等价容斥」求出最终答案.
形式化地, 设题目要求每种等价类对答案的贡献系数构成关于等价类大小的 GF \(C(x)\), 那么我们设单个等价类的容斥系数为 \(G(x)\), 多个被钦定的等价类的合并规则遵从表达式 \(f(G)\), 并希望它们满足
这里 \(f\) 通常比较简单, 于是能找到 \(G\) 的简介表达. 之后在钦定等价类时, 为大小为 \(k\) 的等价类带上 \([x^k]G(x)\) 的容斥系数, 组合时容斥系数求乘积, 就能得到最终的答案.
如果继续扯下去真的玄虚之至了, 我们来看点具体的例子.
\(\textbf{Example 1.1.}\) 「洛谷 P7275」计数 Link & Submission.
\(\textbf{Solution.}\) 考虑一棵合法的树, 其必然能被唯一地剖分为若干条长度 \(>1\) 的树链, 每条树链的结点编号对应一个区间. 反过来, 我们可以先将 \([1,n]\) 划分为若干区间, 再用边将它们连起来, 同时保证不会让两个区间合并.
"不会合并" 这个限制比较麻烦, 先把它扔掉, 此后连接区间的方案数可以用 Prufer 算. 令 \(f(i,j)\) 表示把 \([1,i]\) 划分为长度为 \(l_{1..j}\) 共 \(j\) 段时 \(n^j\prod_{k}l_k\) 之和. 考虑等价容斥, 令 \([x^l]G(x)\) 表示长为 \(l\) 的区间的容斥系数, 那么 \(l\) 的容斥系数总贡献为
我们希望 \(c_l=[l>1]\), 于是
手算一下系数, 发现
于是, 单个区间的 OGF \(H(x)\) 为
欲求的 \(f(n,i)\) 为
最后
直接多项式可以做到 \(\mathcal O(n\log n)\). 当然可以发现这是个线性递推求远项, 所以也能 \(\mathcal O(\log n)\).
\(\textbf{Example 1.2.}\) jiangly 的排列数数题 给定 \(n\), 对于每个 \(k\), 求有多少个 \(n\) 阶排列含有至少一个长度为 \(k\) 的上升段. 也许 \(n\le2\times10^3\)?
\(\textbf{Solution.}\) 容斥成 "不含". 固定 \(k\), 令 \(G_k(x)\) 为容斥系数, 与上题类似地有
答案:
注意 \(G_k(x)\) 只有 \(\mathcal O(n/k)\) 项, 暴力求逆 \(\mathcal O(n^2/k)\), 总共 \(\mathcal O(n^2\log n)\). EI 提出了更厉害的优化.
\(\textbf{Example 1.3.}\) 「LOJ #6728」U 群把妹王 Link & Submission.
\(\textbf{Solution.}\) 来容斥. 令 \(R(x)\) 表示行上容斥系数的 EGF, 那么
选行, 令 \(f_i=[x^i]F(x)\) 表示把 \(n\) 行钦定为 \(i\) 个等价类 (等价类间可能存在等价关系) 的方案数, 那么
选列, \(C(x),g_i=[x^i]G(x)\) 类似. 最终答案为
答案倒是好算, 问题是 \(f,g\) 比较麻烦. 注意到
(注意 \(F(z)\) 是 OGF 而非 EGF.) 因为 \(|S|\) 较小, 所以牛迭可以 \(\mathcal O(|S|n\log n)\) 求出 \(R(x)\) 的复合逆 \(P(x)\). 大概是解这么一个方程:
最后套拉反:
多项式瞎算即可. \(\mathcal O(an\log n+bm\log m)\), 常数巨大.
\(\S2.\) 反射容斥
(名字是别人取的.)
双限制的走折线问题. 即求从 \((0,0)\) 走到 \((n,m)\), 每步位移为 \((1,\pm1)\), 且不能碰到 \(l_1:y=a\) 和 \(l_2:y=b~(a<0<b)\) 的方案数.
我会做只有 \(l:y=b\)! 答案是 \([(0,0)\rightarrow(n,m)]-[(0,0)\rightarrow(n,2b-m)]\). 这里只对第一次碰到 \(l\) 的地方进行了 "反射".
现在有 \(l_1,l_2\), 给出结论, 合法方案数为: 「总方案」\(-\)「撞 \(l_1\) 的方案」\(-\)「撞 \(l_2\) 的方案」\(+\)「撞 \(l_1l_2\) 的方案」\(+\)「撞 \(l_2l_1\) 的方案」\(-\)「撞 \(l_1l_2l_1\) 的方案」\(-\)「撞 \(l_2l_1l_2\) 的方案」\(+\cdots\) 注意 "撞" 是指第一次迎面撞上 ("撞上" 前在合法位置).
如何计数呢? 以「撞 \(l_1l_2l_1l_2\) 的方案」为例, 类似于 \(l:y=b\) 的情况, 我们将终点 \((n,m)\) 依次沿 \(l_2,l_1,l_2,l_1\) 翻折到 \(P\), 计算方案 \((0,0)\rightarrow P\). 注意我们容斥的是撞击点的一段后缀, 所以对于任意非空撞击序列, 其从 \(l_1\) 开始翻和从 \(l_2\) 开始翻必然会被 \(\pm1\) 共计数次, 实际上刚好就是 \(-1\). 所以这个容斥很正确. 最后我们就只需要计算 \(\mathcal O(n/(|a|+|b|))\) 个组合数.
组合意义会引起不安吗 ... 那我们来欣赏一下代数推导. 这里先固定 \(l_1:y=-1\), 也就是经典的 Catalan 数形式. 考虑数轴上的行走, 每步位移为 \(\pm1\). 记从 \(0\) 走到 \(t\) 步到 \(x\), 中途不经过 \(-1\) 的方案数为 \(q_{x,t}\). 我们知道谜底, 但看破不说破.
考虑暴力地把问题塞进 GF 这个袋子里, 令 \(Q(x,t)=\sum q_{x,t}x^it^j\). 容易列出方程
整理一下:
代入 \(x\gets x^{-1}\):
上下作差:
观察系数位置, 可知
其中 \(R(x)\) 的系数仅出现与负指标, 提取 \(Q(x,t)\) 的非负指标位置系数时可忽略. 考察提取过程
我尝试用类似方法推导双限制的反射容斥, 败北了. 可能还是得使用 EI 败北后的反击方法.
\(\textbf{Example 2.1.}\) 「UOJ #424」count Link.
\(\textbf{Solution.}\) 只需要讨论 \(n\ge m\) 的情况. 我们可以通过多叉笛卡尔树唯一确定 \(f\). 众所周知, 设树 \(T\) 的树根为 \(r\), 其儿子 \(u_{1..k}\), 那么我们存在 \(T\mapsto S\in\{\texttt(,\texttt)\}^{2(|T|-1)}\) 的单射. 即构造
所以只需要对这样的序列计数.
如何保证仅仅使用 \([1,m]\) 中的整数? 显然就是要求树高 (叶子到根进过的最多边数) 不超过 \(m\). 对应到括号序列上, 也就是前缀 \(\texttt(~-\) 前缀 \(\texttt)\) 恒 \(\le m\), 当然这个差值也应该恒 \(\ge0\). 令 \(l_1:y=-1,l_2:y=m+1\), 我们就得到了标准的反射容斥问题. 当然你可以用 GF, 不过容易败北.
\(\textbf{Example 2.2.}\) 求含 \(n\) 个 \(1\), \(m\) 个 \(0\) 的序列, 使得任意区间包含 \(01\) 个数差不超过 \(k\). \(n,m,k\le5\times10^7\).
\(\textbf{Solution.}\) 从 \((0,0)\) 走到 \((n+m,n-m)\), 任意两点高度差不超过 \(k\). 实际上只需要最高点与最低点高度差不超过 \(k\). 枚举最低高度 \(a\), 容斥求出最低恰为 \(a\), 最高不超过 \(k-a\) 的方案数, 这一步是 \(\mathcal O((n+m)/k)\) 的. \(a\) 只有 \(k\) 种, 所以复杂度 \(\mathcal O(n+m)\).