容斥
容斥原理
-1型
首先是简单的容斥,即不含系数,直接为总方案减不合法方案
这类问题常常设出 \(dp\) 表示合法的方案数,转移时对于 \(i\) 枚举 \(j\),令 \(j\) 是合法部分,而 \(i-j\) 的部分则是随意填
也是一样的,只不过是放到了二维上
设 \(f[p][i][j]\) 表示第 \(p\) 种棋子占了 \(i\) 行 \(j\) 列的方案数
那么转移为总方案数-\(\sum f[p][x][y]* \binom{i}{x} * \binom{j}{y}\)
注意这里的 \(i=x\) 和 \(j=y\) 不能同时满足
BZOJ4361 isn
首先统计出长度为 \(i\) 的不降子序列数量,这个直接设 \(g[i][j][k]\) 表示前 \(i\) 数取 \(j\) 个且最后一个数为 \(k\) 的方案数,由于每次只需要转移 \(a_i\),可以用树状数组优化到 \(n^2log\)
如果将答案统计为 \(f_ii!\) 会有问题,因为题目限定达到目标后立即停止,那么相当于此时求的 \(f\) 为 \(\ge i\) 的答案,需要减去 \(\ge i+1\) 的答案才行,由于从 \(i+1\) 到 \(i\) 共有 \(i+1\) 种选法,乘到系数上即可
奇减偶加型
经典的容斥式是奇减偶加
容斥后的计算式发现是 \((n-k)!\),其中 \(k\) 为链数
可以发现这个表达式是单一的,那么考虑对于相同的 \(i\) 的贡献一起算,跑一个树形背包
AT3728 [ARC087D] Squirrel Migration
首先肯定是多次经过重心的模式
考虑统计方案数,运用容斥,计算出 \(f_i\) 表示至少 \(i\) 个不合法的
那么 \(ans=\sum (-1)^if_i(n-i)!\)
对于每一棵子树,若有 \(i\) 个不合法的,那么贡献 \(\binom{s}{i}^2i!\),把这个背包进去即可
获胜的条件是那 \(m\) 个人均不是需要 \(pk\) 的 \(n\) 轮中的获胜者
考虑容斥,强制集合 \(S\) 的获胜者是关键点
状压去求
考虑将 \(m\) 个人从大往小插入
那么两种转移,一种放进以前的堆 \(f[i][S]=f[i-1][S]\)
另一种新开一个,加入比 \(a_i\) 大的数(这是从大往小的优势就显现出来了)
\(f[i][S]=f[i-1][S]*\binom{all-S-a_i}{2^j}*(2^j)!\)
同时另一个巧合是状态为 \(S\) 中恰好有 \(S\) 个点
AT5149 [AGC036F] Square Constraints
式子最大的作用其实就是提供了上下界单调的性质以及一些巧合,因此没必要在公式上下功夫
可以结合实际意义,相当于是两个同心圆中的圆环部分作为限制
有两个限制怎么计算?
这让我们想到容斥,因为任何一个单独的限制都是平凡的
于是现在去计算强制一些点选择内圆作为上边界,其余都只有外圆作为上边界限制的方案数
写出来如果只有上界的表达式:
对于一组单增的 \(r\),方案为 \(\prod (r_i-i+1)\)
考虑把这个式子融进 \(dp\) 里,可以发现 \(i\) 是 \(r_i\) 的排名,那么也就是说只需要知道某一种方案下上界的一种顺序即可
但是容斥肯定不能去枚举子集,那么只能将某一个值的方案一起计算
那么这个排名也需要动态计算
这时候就又有巧合了:对于 \([0,n)\) 中选择外圆作为上界的,一定在 \([n,2n)\) 之后
那么可以按照内圆/外圆的边界作为关键字对左右两侧混合排序,这样无论左边怎样决策,对于每一个组的相对大小是没有任何影响的
设 \(f[i][j]\) 表示前 \(i\) 个选 \(j\) 个的方案数,可以发现 \(dp\) 到每一个点的时候排名是水到渠成的(其中还有固定外层的 \(k\) 的功劳),可以愉快地转移啦!
题意: 有 \(n\) 个机器人排成一排,有 \(m\) 个时刻,每个时刻每个机器人有 \(1/2\) 的概率向右走一步,有 \(1/2\) 的概率在原地不动,问所有机器人不相撞的概率
首先转化为统计方案数
考虑相撞问题的一种常见解决方式——不管
于是枚举排列,容斥系数为逆序对数奇偶性
表达式为 \(\prod\binom{m}{y_i-x_i}\)
直接枚举排列肯定行不通
那么改为按顺序加入+状压的模式即可
图的计数
- 建造游乐园
求 \(n\) 个点的欧拉图数量
欧拉图等于度数为偶数的图减去不连通的图
度数为偶数,可以先拿出一个点用来调和,剩下的随意连边,最后一个点总能补成偶数度
那么 \(g_i=2^{\binom{n}{2}}\)
考虑 \(f\) 的转移:\(f_i=g_i-\sum f_jg_{i-j}\binom{i-1}{j-1}\)
即拿出来一部分强制不连通,剩下的随意,组合数用来表示任意选点
hdu4997 Biconnected
题意:一些边不能选,其余的边有多少种选择方式使得整张图构成边强连通图。
考虑按照连通图计数的朴素容斥来统计
设 \(f_S\) 表示 \(S\) 形成的总图数,\(g_S\) 表示 \(S\) 形成的连通图数,\(h_S\) 表示 \(S\) 形成一个边双的数量,\(dp_{S,T}\) 表示 \(S\) 和 \(T\) 进行连边形成边双的方案数
那么 \(h_S=g_S-\sum h_Tdp_{T,S-T}\)
\(dp_{S,T}=\sum tot_{S,i}g_idp{S,T-i}\)
注意其中所有的转移一定要保证 \(lowbit\) 包含于枚举的子集中
沿用类似的思路,详见 这里
uoj37 主旋律
题意:无向图有多少边的子集删去之后整个图仍然强联通
仍然不能直接计算,需要统计不是强连通的数量
首先考虑一种暴力的方式是枚举所有缩点后 \(DAG\) 的样子,然后统计每个大点形成强连通的方案数
于是问题在于怎样统计合法 \(DAG\) 的数量
注意到 \(DAG\) 和无向图并不一样,并不能寻找到一个明显的分割点
那么考虑枚举所有无出度的点,但是无法保证另一个集合中都有出度,需要进行一个集合容斥
\(f_S=\sum (-1)^{|T|-1}2^{edge}f[S-T]\)
考虑进行优化,发现并没有必要枚举 \(DAG\),可以直接在图中 \(dp\) 整个式子的容斥系数即可
ARC105F Lights Out on Connected Graph
题意为二分图计数
可以发现其实限制条件是有两个的:二分图以及图连通
图连通按照套路是需要通过容斥解决的,考虑二分图的个数怎样计算
如果枚举两个子集,子集间随意连边,可以保证是二分图,但是注意会算重
但是并不是完全不对,考虑我们计算出的这个东西是什么
可以发现一个有 \(i\) 个连通块的二分图会被计算 \(2^i\) 次
这其实二分图的合法染色方案数!!!
那么把它放进容斥的机器,计算出来的就理应就是一个连通二分图的染色方案
直接愉快地除以二就好啦
基环树计数,并有权值为 \(2^{非叶节点数}\)
首先这个环肯定烦人嘛,先 \(dp\) 出环的个数
直接容斥是很混乱的,需要钦定出一个环上的最小点作为起点
那么每次扩展的时候都需要保证点大于这个起点即可
设 \(f_S\) 表示 \(S\) 是基环树的方案数
那么 \(f_S=g_S-\sum (-1)^{|T|}f_{S-T}E(T,S-T)\)
最终的答案为 \(ans_S=\sum (-1)^{|T|}2^{|S|-|T|}f_{S-T}E(T,S-T)\)
从上面的分析可以看出,即使是在集合的背景下,采用哪种容斥方式需要结合具体情况来判断,关键在于枚举的集合情形是否有交
二项式反演
本质上是一种特殊的容斥,把容斥系数套路化
这个科技一般的使用情境是题目中询问“恰好 \(k\) 个”的方案数,然而在 \(dp\) 或使用组合数时不能很好保证个数
以下是用到的公式:
至少:
至多:
这就是一个比较难受的情况,因为普通的树形 \(dp\) 状态只能保证手动匹配的点对匹配上了,而剩余的点并不知道是否匹配
也就是说,这题的树形背包其实天然地求解的就是“至少”
设 \(f[u][k]\) 表示 \(u\) 子树中至少 \(k\) 个匹配的方案数
\(f[u][k]=\sum f[u][i]\times f[v][k-i]\)
\(f[u][j+1]=f[u][j](s[id]-j)\)
然后套式子就好了
CF1228E Another Filling the Grid
将反演扩展到二维,满足如下关系:
\(f_{i,j}=\sum_{x=i}\sum_{y=j}(-1)^{x-i+y-j}g_{x,y}\)
考虑求 \(g_{i,j}\) 表示至少 \(i\) 行 \(j\) 列不满足
那么 \(g_{i,j}=\binom{n}{i}\binom{m}{j}(k-1)^{n^2-(n-i)(n-j)}k^{(n-i)(n-j)}\)
首先要求所有行列都不同的颜色的方案数
一样的套路,\(g_{i,j}\) 表示至少 \(i\) 行 \(j\) 列相同
那么 \(g_{i,j}=\binom{n}{i}\binom{n}{j}3^{(n-i)(n-j)+1}\)
\(g_{i,0}=\binom{n}{i}3^{i+n(n-i)}\)
\(g_{0,0}=3^{n^2}\)
然后开始大力推式子,还是不推了吧
巨佬的推导
详见 这里
可以发现其推导的本质还是二项式反演
但是这个排序的转化非常巧妙
tricks
"1"的转化
\(\sum deg_i=2m−1\),可以把每个点的权值设为 \(2-deg_i\),使得部分点贡献变为了全局点贡献,比如 这个
一条链上 边-点=1,比如 这个