Links there:CTSC2018假面
题意
有 $N$ 个敌人,每个敌人的血条为 $hp_i$ ,针针会丢 $Q$ 个技能.
技能1:指定一个敌方单位 $id$ ,给出 $u,v$ ,表示有 $\frac{u}{v}$ 的概率命中这个单位并造成1的伤害.
技能2:给出一个敌人的集合 ${ id_i }$ ,大小为 $k$ ,求每一个 $id_i$ 的存活期望.
最后还要求出每个敌人的血量剩余的期望.
(语文水平低下还恳请看原题面)
思路
考虑用 $a[i][j]$ 表示第 $i$ 个敌人剩下 $j$ 的血量的期望.
我们对于每一次技能 $1$ 是可以在 $O(hp[id])$ 内维护出这个 $a[id][j]$ 的,不难理解.
具体如下
$a[id][0] = a[id][0] + a[id][1] * p$ (已经挂了加上只剩下1滴血的这次挂掉的)
$a[id][i] = (a[id][i] (1-p) + a[id][i+1] p)$ (打得到与打不到)
用 $f[i][j]$ 表示前 $i$ 个敌人有 $j$ 个存活的期望.
用 $exist[i]$ 表示技能2中集合第 $i$ 个的存活期望
用 $dead[i]$ 表示技能2中集合第 $i$ 个的死亡期望
那么对于每一个技能 $2$ 本质上是一次询问操作.
通过考虑第 $i$ 个敌人的存活与否 不难有以下的转移
这样的话我们可以对于每一个集合中的元素 都这么暴力跑一遍就可以得到每个的期望.
时间复杂度为 $O(Cn^3 + Qm)$ , $m$ 为最大$hp$值.
只拿到 $70pts$
考虑优化 每一次我们都暴力重新转移 显然很多状态都被浪费了
考虑逆转移
令$f[i][j] = f’[j]$ 表示要转移到的状态. $f’[j]$ 由 $f[j-1],f[j]$ 转移而来
把它改写过来就是
这样每次我们就可以不需要暴力重置状态啦!这样就可以优化成$O(Cn^2+Qm)$
坑点 注意求逆元不要每次都在做的时候getinv(x,Mod)
这样复杂度多了一个log(Mod)
虽然过了题但是还是要小心啊 预处理线推逆元.
Code
1 | //my vegetable has exploded. :( |