P4564 - 假面 题解

这个 CTSC 的题竟然是我自己想出来的,incredible(


Portal

分为两个问题:求每个结界技能每个攻击对象被命中的概率,和求最终每个敌方单位的期望生命值。先考虑后者。

显然只有锁定技能能够造成伤害。我们设敌方单位 \(i\) 被命中的锁定技能个数为 \(x\)。将式子列出来:\(\mathrm E(\max(0,a_i-x))\)。这个外面套了一个 \(\max\),不好线性性展开。于是我们考虑通过期望的定义,求出每个取值的概率。显然取值个数是 \(\mathrm O(v)\) 的,其中 \(v\) 是值域大小。于是我们可以对每个 \(i\) 搞一个背包:\(dp_{i,j}\) 表示敌方单位 \(i\) 在当前时刻生命值为 \(j\) 的概率,在新加进一个锁定技能的时候更新背包的 DP 数组即可。这样一次更新是 \(\mathrm O(v)\) 的,这一部分就是 \(\mathrm O(Qv)\)。最后统计一下答案即可。

然后考虑前一个问题。每个敌方单位被命中,首先要他自己还活着,然后根据活着的总人数来确定他在当前情况下被命中的概率。设他活着的情况下,剩下 \(i\) 个人活着的概率为 \(p_i\),那么总概率就是 \(\sum \dfrac 1ip_i\)。那么我们考虑求出每个敌方单位所对应的 \(p\) 数组。

显然有一个大暴力:对于每个人都跑一遍背包(\(dp0_{j}\) 表示当前不算第 \(i\) 个人的情况下,考虑到当前,有 \(j\) 个人活着的概率,然后转移用每个人存活的概率,这个可以通过当前 \(dp\) 数组得到),这样一次背包是 \(\mathrm O\!\left(n^2\right)\) 的,总复杂度就是 \(\mathrm O\!\left(Cn^3\right)\),再优化掉一个 \(n\) 就可以了。

我们注意到,每个人所对应的背包,是所有人减去他一个人的。那么能否先算出所有人的,再对于每个人,减去他自己这个人呢?也就是背包是否可逆呢?显然,如果要去掉的人是总背包 DP 过程中的最后一个更新它的人,那显然很好去掉,倒推一下即可。而众所周知,背包是顺序无关的,也就是你可以当作它以任意一个人结尾,那就对于每个人就可以倒推了。

讲一下倒推的方法:设更新前的 DP 数组为 \(dp0\),更新后为 \(dp0'\),那我们想要通过 \(dp0'\) 知道 \(dp0\)。转移显然是

\[dp0'_j=(1-alive_i)dp0_j+alive_idp0_{j-1} \]

其中 \(alive_i\) 是第 \(i\) 个人(也就是假定的最后一个更新的人)存活的概率。那么

\[dp0_j=\dfrac{dp0'_j-alive_idp0_{j-1}}{1-alive_i} \]

但是这里还有一个问题:\(1-alive_i\) 可能等于 \(0\),也就是 \(alive_i=1\)。这个需要特判一下。事实上这个简单的一批,不难得到

\[dp0_j=dp0'_{j+1} \]

于是总复杂度 \(\mathrm O\!\left(Qv+Cn^2\right)\)。要注意预处理一些逆元,不然复杂度就多了个 \(\log\)

code

posted @ 2020-12-01 19:52  ycx060617  阅读(86)  评论(0编辑  收藏  举报