# 光棱坦克题解 ## 解法比较 出题人解法枚举最终开火的根,对树做动态规划:把孩子的贡献降序排列,枚举保留的孩子数 $k$ ,用前 $k$ 项之和乘相应衰减系数,再加当前点伤害。固定 $k$ 时显然应选贡献最大的孩子;从叶子归纳即可得到下文的递推。不能屏蔽时保留全部孩子。 Codex(GPT-6)的实现生成显式遍历顺序,再逆序计算,避免深树递归。最坏时间为 $O(n^2\log(n+1))$ ,空间为 $O(n)$ .系数、取整与边界处理见下文。 ## 阻断能力只需区分两种情况 $b=0$ 时不能阻断任何边。$b\ge1$ 时,任意边集都可以被阻断:给森林每个连通分量任选一个根,让每条待阻断边的子节点选择这条父边。每个顶点只有一条父边,因此至多选择一条边,符合名额限制。即使同一顶点周围有很多条边需要阻断,也可以把选择这些边的任务交给相应的孩子。 ## 枚举攻击点 固定初始攻击点为根,只访问它所在的连通分量。树上路径唯一:当非根顶点 $u$ 被击中时,它的父节点已经被击中,孩子尚未被击中。因此,下一步只会沿未阻断的边进入孩子的子树。 设 $f_u$ 为已经击中 $u$ 时,通过预先选定其子树内的阻断方案所能获得的最大期望伤害,包含 $u$ 自身的伤害。若保留通向 $k\ge1$ 个孩子 $v_1,\ldots,v_k$ 的边,则它们的期望贡献为 $$\left(p_u+\frac{1-p_u}{k}\right)\sum_{j=1}^k f_{v_j}$$ 这是因为每个孩子被击中的概率都是 $p_u+(1-p_u)/k$ :全体折射时必然击中,单点折射时以 $1/k$ 的概率被选中。不同孩子的子树互不相交,可以预先为它们分别选择最优阻断方案。孩子之间是否被击中可能相关,但期望的线性性仍然允许我们直接相加。 当 $b=0$ 时必须保留通向全部孩子的边,直接代入它们的数量与 $f$ 值之和;没有孩子时,贡献为零。 当 $b\ge1$ 时,把所有孩子的 $f$ 值从大到小排序,枚举保留数量 $k$ ,用前缀和计算贡献。相同 $k$ 下系数相同且非负,因此选最大的 $k$ 项最优。也考虑不保留孩子,贡献为零。取这些方案的最大贡献,最后加上 $d_u$ . 自底向上计算根的答案,再枚举所有顶点作为根取最大值。程序使用迭代遍历,避免长链递归。 ## 正确性 叶子的最优值是自身伤害。假设所有孩子的最优值均已正确计算。保留的孩子集合确定后,贡献公式中的系数非负,所以让每个孩子采用自己的最优子树方案最优。这些方案作用于不同子树,而且所需的删边集合在 $b\ge1$ 时一定可以实现。 若不能阻断,算法计算唯一允许的孩子集合;若可以阻断,算法枚举所有保留数量,并为每个数量选出最优集合。因此转移既不会漏掉最优方案,也不会使用无法实现的方案。加上自身伤害后得到 $f_u$ ,树形归纳便证明固定根的答案正确。最后枚举所有顶点作为根,覆盖了森林中的全部攻击点。 ## 复杂度与精度 时间 $O(n^2\log n)$ ,空间 $O(n)$ ;孤立点也正常参与比较。使用浮点数计算期望,最后显式执行 $\lfloor V+\delta+0.5\rfloor$ ,不依赖格式化输出的舍入模式。题目保证距离半整数分界至少 $0.2$ . 代码中 `BlockLimit` 对应阻断名额 $b$ ,`RoundingOffset` 对应取整偏移量 $\delta$ .