1 条题解
-
0
E. LeaFall 详细题解
一、问题理解
有一棵 个节点的树。每个节点 以概率 独立倒下(移除自身和邻边),剩余节点形成森林。需要计算期望的叶子对数量(无序,叶子定义为度数为 的节点),结果对 取模。
二、核心公式
设随机变量 = 叶子对数量。由期望线性性:
$$E[X] = \sum_{1 \le u < v \le n} P(\text{节点 } u \text{ 和 } v \text{ 都是叶子}) $$标程的核心思想:
- 先假设所有顶点对独立,计算近似期望
- 再对距离 的顶点对进行修正(因为只有这些顶点的事件会相互依赖)
三、符号定义
- 表示节点 倒下的概率
- 表示节点 未倒下的概率
四、单个节点成为叶子的概率
节点 成为叶子,当且仅当:
- 未倒下
- 的邻居中恰好有一个未倒下,其余全部倒下
设 为 的邻居集合。
先计算 : 未倒下且所有邻居都倒下的概率:
然后, 成为叶子的概率 = 对每个邻居 ,让 成为那个唯一未倒下的邻居:
$$p2[i] = \sum_{u \in N(i)} \left( stay[i] \cdot (1-pr_u) \cdot \prod_{\substack{w \in N(i) \\ w \ne u}} pr_w \right) $$注意到:
$$stay[i] \cdot \prod_{\substack{w \in N(i) \\ w \ne u}} pr_w = \frac{p1[i]}{pr_u} $$所以:
$$p2[i] = \sum_{u \in N(i)} \frac{p1[i]}{pr_u} \cdot (1-pr_u) = p1[i] \cdot \sum_{u \in N(i)} \frac{1-pr_u}{pr_u} $$标程中的计算正是这个公式:
p1[i] = sub(1, p[i]); for (int u : adj[i]) p1[i] = mul(p1[i], p[u]); for (int u : adj[i]) { int term = mul(p1[i], mul(inv(p[u]), sub(1, p[u]))); add2(p2[i], term); }
五、初始期望(假设独立)
如果所有顶点对独立,则:
$$E_{\text{indep}} = \sum_{u<v} p2[u] \cdot p2[v] = \frac{1}{2}\left( \left(\sum p2[i]\right)^2 - \sum p2[i]^2 \right) $$标程第一段循环实现了这个:
int ans = 0, sum = 0; for (int i = 1; i <= n; i++) { add2(ans, mul(p2[i], sum)); add2(sum, p2[i]); }这里
ans累积的是 ,即 。
六、修正距离为 的顶点对(相邻节点)
对于相邻节点 ,事件“ 是叶子”和“ 是叶子”不独立,需要重新计算联合概率并替换独立近似。
联合概率: 和 都是叶子
条件:
- 未倒下, 未倒下
- 的邻居中恰好一个未倒下(这个未倒下的邻居必须是 ,否则 会有其他未倒下邻居)
- 的邻居中恰好一个未倒下(这个未倒下的邻居必须是 )
- 其他所有邻居(除了 和 彼此)必须全部倒下
设 为 的邻居集合, 为 的邻居集合。
则联合概率为:
$$\begin{aligned} P(\text{leaf}_u \land \text{leaf}_v) &= stay[u] \cdot stay[v] \cdot (1-pr_v) \cdot (1-pr_u) \\ &\quad \cdot \prod_{w \in N(u) \setminus \{v\}} pr_w \cdot \prod_{w \in N(v) \setminus \{u\}} pr_w \end{aligned} $$注意 $stay[u] \cdot \prod_{w \in N(u) \setminus \{v\}} pr_w = \frac{p1[u]}{pr_v}$。
所以:
$$P(\text{leaf}_u \land \text{leaf}_v) = \frac{p1[u]}{pr_v} \cdot \frac{p1[v]}{pr_u} \cdot (1-pr_u)(1-pr_v) $$标程中:
int pi = mul(p1[i], inv(p[u])); // = p1[i] / p[u] int pu = mul(p1[u], inv(p[i])); // = p1[u] / p[i] add2(ans, mul(pi, pu)); // 加上精确联合概率 sub2(ans, mul(p2[i], p2[u])); // 减去之前独立的贡献
七、修正距离为 的顶点对(经过中间节点 )
设 和 是 的两个不同邻居,即 是 和 的公共邻居。需要计算 。
情况分析: 和 成为叶子的条件涉及 的状态。
标程将 是否倒下分开处理:
情况 1: 未倒下
则 成为叶子的条件:
- 未倒下
- 的邻居中恰好一个未倒下,且这个邻居必须是 (因为 未倒下, 的其他邻居必须全部倒下)
所以 成为叶子的概率(给定 未倒下)为:
因为 ,除以 去掉 的因子,再乘以 是因为 未倒下。
标程中:
int pu = mul(p1[u], inv(p[i])); // = p1[u] / p[i] add2(ans, mul(sum, pu)); add2(sum, mul(pu, sub(1, p[i])));情况 2: 倒下
则 成为叶子的条件:
- 未倒下
- 的邻居中恰好一个未倒下,且这个邻居不能是 (因为 已倒下),所以必须是 的其他某个邻居
计算 成为叶子且 倒下的概率 = 。
其中 $P(\text{leaf}_u \land i \text{ 未倒下}) = \frac{p1[u]}{pr_i} \cdot (1-pr_i)$。
标程中:
int pu = sub(p2[u], mul(p1[u], mul(inv(p[i]), sub(1, p[i])))); add2(ans, mul(sum, pu)); add2(sum, mul(pu, inv(p[i])));
八、算法流程总结
- 读入 、每个节点的 、树的边
- 计算
- 计算 :节点 未倒下且所有邻居倒下的概率
- 计算 :节点 成为叶子的概率
- 初始化
ans为所有无序对的独立贡献 - 对每条边 (距离 ):
- 加上精确联合概率
- 减去独立贡献
- 对每个节点 ,处理以 为中间节点的距离 的顶点对:
- 未倒下时的情况
- 倒下时的情况
- 输出
ans
九、复杂度分析
- 预处理 :
- 初始贡献:
- 距离 修正:(每条边一次)
- 距离 修正:,最坏情况星形树可能 ,但由于 在稀疏图中通常可控,且 时仍可接受
十、示例验证
以题目第二个测试用例为例:
- ,树为 ,所有
- 计算得 ,
- 初始独立贡献:$p2[1]p2[2] + p2[1]p2[3] + p2[2]p2[3] = \frac{1}{8} + \frac{1}{16} + \frac{1}{8} = \frac{5}{16}$
- 修正后得到 ,与题目一致
十一、总结
要点 说明 核心思想 线性期望 + 独立近似 + 局部修正 关键公式 $p2[i] = p1[i] \sum_{u \in N(i)} \frac{1-pr_u}{pr_u}$ 修正范围 只修正距离 的顶点对 时间复杂度 ,实际可过 模运算 使用模逆处理分数
- 1
信息
- ID
- 7235
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者