P5405 [CTS2019] 氪金手游 题解
CTS2019 压轴题果然是有很大的难度的。
题面
给定一颗 \(n\) 个点的树,每条边有一个方向。
现在我们不断从 \(n\) 个点中随机抽取一个,直到所有的点都被抽取至少一次。每个点有一个取值 \(p_i\),值为 \(1,2,3\) 中的一个,代表这个点被抽中的概率为 \(\frac{p_i}{\sum_j p_j}\)。
记 \(i\) 号点在第 \(T_i\) 次抽取时第一次被抽中,现在想要问你,满足"对于树上的任意一条有向边 \(u_i \to v_i\),满足 \(T_{u_i}<T_{v_i}\)"的概率。
注意,\(p_i\) 的值不是给定的,它在一开始以 \(P_{i,j}\) 的概率取值为 \(j\),之后就不再变化。
数据范围:\(n \le 1000\)。
思路 - 1
思路来自 xtr 老师,为什么这么复杂……但是感觉还是跟题解区都不太相同的做法,就写一下吧。
看懂这个题目花了我 5 分钟的时间,主要是因为这道题要素太多了!!!
题目中的概率模型过于复杂,考虑暂时简化一下题目:假设 \(p_i\) 的值在一开始给定。
而且,题目中的树边并不是统一的方向。我们先假设若这棵树是一棵外向树,该如何做出来。
设这棵树的根结点为 \(r\),显然要满足条件,\(r\) 必须要最先抽中,这样的概率就是 \(\frac{p_r}{\sum_j p_j}\)。而因为子树之间是互相独立的,所以所有的子树都要满足这个顺序:先是根结点,然后才是其他的点。
不妨设 \(S_i\) 为 \(i\) 的子树,答案就是:
但是实际上树的方向并不是那么统一,不难发现主要是因为“父亲比儿子先被选”和“儿子比父亲先被选”是两种对立且可以同时存在的限制。采用容斥的思路,不妨将这两个限制改为“父亲比儿子先被选”和没有限制两种。
假设有“父亲比儿子先被选”的限制的树边集合是 \(S\),于是,限制树现在变为了若干边方向统一的连通块。显然每一个连通块可以独立计算答案,也就是上面的式子。
这是我们的第一步。接下来考虑第二步:判断如何确定权值使得这些概率加权之后的和为所求答案。考虑我们现在统计的是什么东西,就是满足 \(S\) 中的位置有“父亲比儿子先被选”的限制、其他位置不加限制的概率,不妨记做 \(f_S\)。同时将满足恰好 \(S\) 中的位置有“父亲比儿子先被选”的限制的概率记为 \(g_S\)。
假设题中给定的需要满足“父亲比儿子先被选”的限制的树边集合是 \(S\),那么所求答案就是 \(g_S\)。利用容斥原理可得:
考虑重新回到题目,关注 \(p_i\) 的取值并非开始就确定的问题。那么不妨枚举所有可能的取值,将它们的答案乘以概率相加:
现在,这个式子已经完全表示了 \(S\) 的答案。接下来,我们只需要着手于化简并求解这个式子。
思路 - 2
在前面,我们通过容斥得到了答案的形式:
其中,\(S\) 代表题目中给出的需要满足父亲先于儿子的限制的位置集合,而 \(Sr_i\) 则表示根据 \(T\) 确定的连通块中,以 \(i\) 为根的子树形成的点集。
注意到 \(|S|\) 为常量,因此可以将 \((-1)^{|S|}\) 从和式中提出化简结构。同时,也可以将两个 \(\prod\) 进行合并:
考虑使用“分离因子”方法的启发,考虑能否将 \(\prod\) 中的某一项取值并分离这一公共部分。
由于树自带的特殊性质,我们应该先尝试分离根的部分。假设根为 \(r\),那么我们需要首先枚举 \(\prod\) 中 \(r\) 的部分 \(\frac{P_{r,p_r}p_r}{\sum_{j \in Sr_r}p_j}\) 具体的值,有两个值需要确定:\(p_r\) 和 \(\sum_{j \in Sr_r}p_j\)。
不妨设 \(j=p_r,k=\sum_{j \in Sr_r}p_j\),那么 \(j,k\) 为特定值的那部分就有一个公共因子 \(\frac{P_{r,j}j}{k}\):
考虑去掉公共因子之后的部分,试图将其变成一个子问题。为了接下来写得方便,我们设 \(son_i\) 表示结点 \(i\) 的所有儿子构成的集合,\(Tr_i\) 表示原来树上以 \(i\) 为根的子树(这东西和 \(Sr_i\) 是不同的两个东西,要注意做好区分)
结合树形 \(dp\) 的经验,我们容易想到对于树上的 \(i \not = r\) 的贡献,相比于像序列那样整体递归为单个规模最小的子问题,更适合对每一个 \(r\) 的儿子 \(y\) 的子树分别递归每一个子问题,然后考虑将不同子树的答案合并。
因此,我们先来尝试对上式将不同的 \(y\) 子树的部分分离出来。
首先考虑连乘的部分 \(\prod_{i \not = r} \frac{P_{i,p_i}p_i}{\sum_{j \in Sr_i} p_j}\) 如何分离,这一部分是简单的。因为 \(i\) 所在 \(y\) 子树是不同的,将其划分成若干部分分别连乘:
那么,原来的式子就转化为了这样:
接下来考虑分离 \(\left[\sum_{j \in Sr_r} p_j = k\right]\) 的部分,这表明枚举 \(k\) 后,我们这里只关心 \(\sum_{j \in Sr_r} p_j\) 取值为 \(k\) 的那些情况。然后考虑该如何分离到各个 \(y\) 子树当中。
我们不妨来仔细分析一下 \(Sr_r\) 的结构,\(Sr_r\) 表示 \(T\) 集合中 \(r\) 所在连通块中的子树。那么 \(r\) 的所有儿子 \(y\) 中,首先有和 \(r\) 在同一连通块的,也有不在的。我们设 \(TS_r\) 表示那些和 \(r\) 在统一连通块的儿子集合。
那么可以认为 \(Sr_r\) 的这个连通块的子树,是由下面几部分构成的:
根据我们得到的这个 \(Sr_r\) 的结构,我们有:
其中,\(k_y = \sum_{j \in Sr_y}p_j\) 表示对于 \(y\) 的连通块子树的 \(p_j\) 之和。于是,我们的 \(\sum_{j \in Sr_r}p_j = k\) 的条件,实际上转化为了 \(\sum_{y \in TS_r} k_y = k-j\)。这启发我们尝试对于每个 \(y\) 的 \(k_y\) 进行限制,求解 \(k_y\) 固定为某个值的贡献之和,这和我们现在对 \(r\) 做的关于 \(k\) 的假设是类似的。
再挂一遍最近推出来的式子:
根据之前的讨论,我们可以将对于 \(k\) 的限制转化为对于每个 \(k_y\) 的限制。由此,我们先枚举所有总和为 \(k-j\) 的 \(k_y\) 的分配方式,然后变成对于每个 \(k_y\) 的要求:
注意,这里的 \(\sum_{y \in TS_r}k_y=k-j\) 只对于 \(y \in TS_r\) 的儿子 \(y\) 有限制。
再考虑将 \((-1)^{|T|}\) 的部分进行分离。为此,我们还是先分析 \(T\) 的结构。\(T\) 组成现有连通块的那些边。那么,\(\{(r,y)|y \in TS_r\}\) 就是 \(T\) 的一部分,而其余的部分可以仿照 \(Sr_r\) 的结构,分解为各个 \(y\) 子树内部的边 \(T_y\),所以有:
于是,我们得到 \(|T|=|TS_r|+\sum_{y \in son_r} |T_y|\),这样就可以分离为:
利用 \(T\) 的结构,我们还可以分离 \(S \subseteq T\) 的枚举部分。令 \(SS_r\) 表示 \(S\) 中 \(r\) 与儿子的边,\(S_y\) 表示 \(S\) 中在 \(y\) 子树内部的边,则 \(T\) 的枚举可以分为 \(r\) 与儿子的边 \(TS_r\) 与各个 \(y\) 子树内部的边 \(T_y\) 几部分。因此,我们可以将 \(S \subseteq T\) 分离,式子变为:
最后,将 \(p_i\) 的枚举也分离到子树内,我们就完成了分离的过程,将问题转变为各个 \(y\) 子树内部的问题:
至此,我们终于将原问题分离为类似的子问题了。就是最终的式子有一些复杂。
思路 - 3
考虑使用 \(dp\) 来配合容斥。考虑设计状态。
显然,可以令 \(dp_{y,k_y}\) 表示对于以 \(y\) 为根的子树的子问题而言,满足 \(\sum_{j \in Sr_y} p_j = k_y\) 的情况的贡献和:
原式就可以转化为:
不过,想到这一步,想要枚举所有 \(TS_r\) 和 \(\sum_{y \in TS_r} k_y = k-j\) 的组合的复杂度仍然是过高的,但因为我们已经将原来的式子拆分成了一个超长、而且及其零碎的式子,我们已经无法再分离贡献。
为了进行进一步的化简,我们需要回顾带权的乘法原理的概念。具体地说,现在想求所有方案 \(S\) 的权值和 \(\sum_S W_S\),而每个方案 \(S\) 都可以被分解为独立的 \(n\) 步 \(S_1,S_2,...,S_n\),并满足其权值就是每个步骤的权值的乘积,即 \(W_s = \prod_{i=1}^n W_{S_i}\)。
那么根据乘法原理,我们就可以将原问题分解为 \(n\) 个部分,分别求解合法的 \(S_1,S_2,...,S_n\) 的权值和:
根据上面的公式,我们可以直观的认为,我们能够在每个步骤相对都是独立的情况下,交换求和和乘积的顺序。
再次回到刚刚的转移式:
注意到当枚举到 \(TS_r\) 是,\(son_r \setminus TS_r\) 中的 \(y\) 的 \(k_y\) 并没有被和为 \(k-j\) 的条件限制,实际上可以任意取值,因此,这部分的 \(k_y\) 的取值显然是彼此独立的,我们可以使用乘法原理,交换求和和乘积:
我们又发现我们可以将外面的因子 \((-1)^{|TS_r|}\) 合并到 \(TS_r\) 的计算中,得到:
现在,有一个重要的问题是存在 \(\sum_{y \in TS_r} k_y = k-j\) 的限制,这使得 \(k_y\) 的取值不是彼此独立的,不能直接用乘法原理交换 \(\sum\) 和 \(\prod\) 进行化简。
不过,\(\sum_{y \in TS_r} k_y = k-j\) 这种限制若干个变量的和为定值的情况,可以让我们联想到多个多项式的乘积,由此,我们想到使用生成函数来处理。我们令 \(DP_y = \sum_k dp_{y,k} \times \mathbf{x}^k\),则上面的式子可以转化为:
现在,还剩下复杂度较高的美剧是关于 \(TS_r\) 的。由于不同的 \(y\) 的贡献仍然独立,我们还是使用乘法原理,将其转化为:
最终,将 \(r\) 一般化为 \(x\),并令 \(P_i = \sum_{j=1}^3 P_{i,j}j \cdot \mathbf{x}^j\),我们就得到了 \(DP\) 数组的转移方程:
这就是完整解法。至此,我们已经做出来了这道题。
复杂度分析
整理一下复杂度。
容易发现 \(k_y\) 作为 \(Sr_y\) 子树内 \(p_i\) 的和,是 \(O(|Tr_y|)\) 的,故利用平方算法进行多项式乘法,通过将代价理解为跨越点集的点对数,即可得到总的时间复杂度是 \(O(n^2)\) 的,可以通过。

浙公网安备 33010602011771号