Atcoder Grand Contest 041 F - Histogram Rooks
考虑容斥。我们钦定一些格子组成的集合不能被覆盖,设为 \(A\)。把与 \(A\) 中的点同行同列的点抠掉,剩余的点则是可放可不放的,总方案数就是 \(2^{\text{剩余点的个数}}\),乘以 \((-1)^{|A|}\) 并求和即可。
这个做法直接优化显然不行。我们考虑设 \(A\) 中的点所在的列组成的不可重集为 \(S\),我们枚举 \(S\) 是什么,那么考虑每一个行连续段计算方案数,分两种情况讨论:
- 这一行里没有任何属于 \(A\) 的格子,那么设 \(c\) 为这一行中不属于 \(S\) 的列的个数,那么这种方案的容斥系数乘以方案数就是 \(2^c\)。
- 这一行有至少一个格子属于 \(A\),那么枚举这一行中属于 \(A\) 的格子的数量 \(d\),容斥系数 \((-1)^d\),方案数 \(\dbinom{c}{d}\),把它们求和可以得到 \(\sum\limits_{d=1}^c\dbinom{c}{d}(-1)^d\),其值为 \(-[c>0]\)。
两者加起来就是这一行的方案数。
但是这个做法有一个问题,就是我们不能保证 \(S\) 中每一列都有至少一个格子属于 \(A\)。
考虑再进行一层容斥。枚举集合 \(T\) 满足 \(T\subseteq S\) 且 \(T\) 中的列都没有属于 \(A\) 的格子,那容斥系数自然是 \((-1)^{|T|}\),这样每一行的方案数也要进行相应的改变:
- 这一行里没有任何属于 \(A\) 的格子,那么设 \(c\) 为这一行中不属于 \(S\) 的列的个数,那么这种方案的容斥系数乘以方案数就是 \(2^c\)。
- 这一行有至少一个格子属于 \(A\),设 \(c'\) 为这一行中属于 \(S\) 但不属于 \(T\) 的列的个数,那么类比之前的过程可知方案数为 \(-[c'>0]\)。
而我们发现,这个棋盘实际上可以被看作笛卡尔树的形状。即,对于每一个行连续段,它对应的列实际上是笛卡尔树上一个区间。因此考虑对 \(h\) 建笛卡尔树,然后设 \(dp_{i,j,0/1}\) 表示 \(i\) 子树内有 \(j\) 个属于 \(S\) 的列,是/否有属于 \(S\) 但不属于列的所有 \((S,T)\) 的方案数乘以容斥系数之和。转移是背包合并,总复杂度就是 \(O(n^2)\)。