题解 ABC234G Divide a Sequence

第一次在赛场上想出 G 的做法!
可惜太慢了到最后 5 分钟不到才写完来不及调了

首先可以得到一个 \(O(n^2)\) 的 dp 式子 \(f_i = \sum f_{j} \times \operatorname H(j+1..i)\)\(\operatorname H\) 是极差,初始条件 \(f_0 = 1\)

这个式子因为要枚举 \(j\)\(\operatorname H\) 值随着 \(j\) 的变化而变化,所以很难用什么东西直接维护。观察一下贡献的本质是什么,可以发现一个 \(f_j\) 的值在区间最大值增加 \(x\) 的时候对后面的贡献增加了 \(f_j \times x\),最小值减少的时候同理。那么可以开一个值域线段树,把 \(f_i\) 挂到当前的区间最大值上面去,当区间最大值变得更大的时候计算比它小的对它产生的贡献即可。
具体来说就是一个线段树维护 \(\sum i \times w_i\),一个线段树维护 \(\sum w_i\),计算变化到 \(x\) 的贡献的时候只需增加 \(\left(x \times \sum w \right) - \left( \sum i \times w_i \right)\) 就可以了。线段树只需要支持区间覆盖区间求和即可,加的时候可以先查询然后加上再覆盖上去。

提交记录

https://atcoder.jp/contests/abc234/submissions/28432611

然后就发现运行时间是其他人的十几倍。

其实根本不需要用四个线段树去维护,直接用栈,每次加入新数的时候把栈顶往下能覆盖的都给覆盖掉后更新答案就可以了。

所以还是没想到正解

posted @ 2022-01-09 16:59  Acfboy  阅读(148)  评论(0编辑  收藏  举报