带标号的各种图计数学习笔记

参考: 王迪2013年国家集训队论文浅谈容斥原理
这篇论文后面可能会完整地学习一次, 写一篇学习笔记. 但至少这篇文章里面只是涉及到其中的一些内容, 一些原理性的东西可能就不求甚解了.

预备知识: 容斥原理的一般化

对于两个关于集合的函数\(f(S)\)\(g(S)\), 假如有

\[f(S) = \sum_{T \subseteq S} g(T) \]

那么就有

\[g(S) = \sum_{T \subseteq S} (-1)^{|S| - |T|} f(T) \]

证明这里无法给出.
我们还可以对其稍作变形, 无非就是把\(\subseteq\)改成\(\supseteq\), 这里不再赘述.

带标号的DAG计数

这里开始进入正题了.
我们给定一个\(n\), 对\(n\)个点的有标号的有向无环图(DAG)进行计数, 答案模\(10^9 + 7\). 数据规模满足\(n \le 5 \times 10^3\).
考虑动态规划. 注意到有向无环图中必然存在一些出度为零的点, 因此我们用\(f(i, j)\)表示总共有\(i\)个点的有向无环图, 并且满足出度为零的点的数量为\(j\)的DAG数量, 则有递归式

\[f(i, j) = \left(\begin{array}{} j \\ i \end{array}{} \right) \sum_{k = 1}^{i - j} (2^j - 1)^k 2^{j(i - j - k)} f(i - j, k) \]

分析这则式子的含义: \(\left( \begin{array}{} i \\ j \end{array}{} \right)\)表示在\(i\)个点中任意选出\(j\)个点的情况数; \(\sum_{k = 1}^{i - j}\)表示枚举去掉这\(k\)个点后的图有多少个点出度为\(0\); \((2^j - 1)^k\)表示原图中这些出度为\(0\)的点至少要与新图中的\(k\)个点连一条边, 否则其出度还是为\(0\); \(2^{j(i - j - k)}\)显而易见, 不解释了; \(f(i - j, k)\)递归上一层图的情况. 时间复杂度: \(O(n^3)\).
考虑是否有复杂度更优的算法? 注意到我们在定义\(f(i, j)\)时使用的是"恰好有\(j\)个点出度为零", 考虑修改这个限制: 我们令\(g(i, S)\)表示总共\(i\)个点, 且\(S\)这个集合中的点出度为零, \(h(i, j)\)表示总共\(i\)个点, 且至少有\(S\)这个集合中的点出度为零. 那么我们可以得到如下递归式:

\[h(i, S) = 2^{(i - |S|)|S|} h(i - |S|, \emptyset) \]

再考虑\(g\)\(h\)的关系:

\[h(i, S) = \sum_{T \supseteq S} g(i, T) \\ g(i, S) = \sum_{T \supseteq S} (-1)^{|S| - |T|} h(T) \]

然而我们的目的在于求\(h(n, \emptyset)\), 因此有

\[\begin{aligned} h(n, \emptyset) &= \sum_{T \ne \emptyset} \text{\\ 为什么T不能为空集? 因为DAG中必定存在出度为0的点} \\ &= \sum_{m = 1}^n \sum_{|T| = m} f(n, T) \end{aligned} \]

再代入之前推导出的

\[g(i, S) = \sum_{T \supseteq S} (-1)^{|S| - |T|} h(T) \]

我们有

\[\begin{aligned} h(n, \emptyset) &= \sum_{m = 1}^n \sum_{|T| = m} \sum_{S \supseteq T} (-1)^{|S| - |T|} g(n, S) \\ &= \sum_{m = 1}^n \sum_{|T| = m} \sum_{S \supseteq T} (-1)^{|S| - |T|} 2^{(n - |S|)|S|} h(n - |S|, \emptyset) \\ &= \sum_{m = 1}^n \sum_{|T| = m} \sum_{k = m}^n \left( \begin{array}{} n - m \\ k - m \end{array}{} \right) (-1)^{k - m} 2^{(n - k)k} h(n - k, \emptyset) \\ &= \sum_{m = 1}^n \left( \begin{array}{} n \\ m \end{array}{} \right) \sum_{k = m}^n \left( \begin{array}{} n - m \\ k - m \end{array}{} \right) (-1)^{k - m} 2^{(n - k)k} h(n - k, \emptyset) \end{aligned} \]

到这里好像就没法继续化简了. 其实不然.

\[\begin{aligned} &\ \sum_{m = 1}^n \left( \begin{array}{} n \\ m \end{array}{} \right) \sum_{k = m}^n \left( \begin{array}{} n - m \\ k - m \end{array}{} \right) (-1)^{k - m} 2^{(n - k)k} h(n - k, \emptyset) \\ &= \sum_{k = 1}^n \sum_{m = 1}^k \left( \begin{aligned}{} n \\ m \end{aligned} \right) \left( \begin{array}{} n - m \\ k - m \end{array}{} \right) (-1)^{k - m} 2^{(n - k)k} h(n - k, \emptyset) \\ &= \sum_{k = 1}^n 2^{k(n - k)} h(n - k, \emptyset) \sum_{m = 1}^k (-1)^{k - m} \left( \begin{aligned}{} n \\ m \end{aligned} \right) \left( \begin{array}{} n - m \\ k - m \end{array}{} \right) \\ \end{aligned} \]

考虑如何处理上面的组合数: 我们有如下结论

\[\left( \begin{aligned}{} n \\ m \end{aligned} \right) \left( \begin{array}{} n - m \\ k - m \end{array}{} \right) = \left( \begin{array}{} n \\ k \end{array} \right) \left( \begin{array}{} k \\ m \end{array} \right) \]

我们有

\[\begin{aligned} &\ \sum_{k = 1}^n 2^{k(n - k)} h(n - k, \emptyset) \sum_{m = 1}^k (-1)^{k - m} \left( \begin{aligned}{} n \\ m \end{aligned} \right) \left( \begin{array}{} n - m \\ k - m \end{array}{} \right) \\ &= \sum_{k = 1}^n 2^{k(n - k)} h(n - k, \emptyset) \left( \begin{array}{} n \\ k \end{array} \right) \sum_{m = 1}^k (-1)^{k - m} \left( \begin{array}{} k \\ m \end{array} \right) \\ &= \sum_{k = 1}^n 2^{k(n - k)} h(n - k, \emptyset) \left( \begin{array}{} n \\ k \end{array} \right)[(1 - 1)^k - 1^0 (-1)^k] \text{ 根据二项式定理变形} \\ &= - \sum_{k = 1}^n 2^{k(n - k)} h(n - k, \emptyset) \left( \begin{array}{} n \\ k \end{array} \right)(-1)^k \\ &= \sum_{k = 1}^n (-1)^{k - 1} \left( \begin{array}{} n \\ k \end{array} \right) 2^{k(n - k)} h(n - k, \emptyset) \end{aligned} \]

这样一来, 我们就把计算的时间复杂度降低到了\(O(n^2)\), 问题解决.

posted @ 2017-08-19 16:15  Zeonfai  阅读(838)  评论(0编辑  收藏  举报