题解 P4231 【三步必杀】
orangebird · · 题解
我们来分数据范围看看做法:
首先是1<=n,m<=1000
暴力模拟即可,不必多说。
然后是s=e。这意味着题目变成多次区间加,然后询问。那么利用差分即可解决。
l.......... r+1
s..........-s
这时求前缀和,相当于给[l,r]中的每个数字都增加了s。
接下来看看正解,顺便也解决1<=n<=1e5,1<=m<=1e5的情况。
因为是等差数列,所以我们还是利用差分。
经过一次差分,我们发现对于一个l,r,s,e操作,先求出公差d,然后可以变成这样:
l l+1 l+2.......r r+1
s d d .......d -s-(r-l)*d
就变成了两次单点加和一次区间加了。那么怎么办呢?
可以用树状数组/线段树来维护区间,每次操作O(logn),这就是1e5的做法了。
那么正解呢?再差分一次就好(应该没人想到这一步还想不到正解吧)。
l l+1 .......... r+1 r+2
s d-s -(r-l+1)d-s s+(r-l)d
最后求两次前缀和就能获得原数组了。
这样每次操作是O(1)的,总复杂度O(n+m),顺利通过。
后续剧情
(四)三步必杀
荷取不断地思考着.... "让我看看,每次产生的伤害都是一个等差数列?"
"等差数列嘛.....似乎看不出什么玄机呢。"
"但是,如果不是等差数列,而是对每一个柱子产生的伤害相同,情况可能会不一样。"
"如果对每个柱子产生的伤害相同,我只要记录下伤害开始和结束的位置就可以了" "具体怎么样呢..."
"嗯,把柱子从左到右编号 1,2,3...,伤害开始的地方记做 L,结束的地方记做 R。 在 L 这里记一个 1,就表示从现在开始,往右边的柱子都受到了 1 的伤害。
但是这么做的话,在 R 右侧的柱子受到的伤害就会凭空多出 1。
那么,只要在 R 右边的那个柱子标记一个-1,就可以抵消掉了。
而且这样的标记是独立的,可以累加! "
"这样的话,每次攻击我只需要在一个临时序列 S 上改两个数字,等到最后从左到右求 一遍和就可以得到结果了
这个 S 序列通过一次记录两个数,得到了每次伤害对其之后柱子损伤程度的影响 由于用到做差与求和,那我就先把这个 S 叫差分序列,从左到右求和后的序列叫前缀 和序列吧。
嗯,很不错呢,很不错呢。"
荷取的眼睛闪着光芒。
"可真正的伤害不是固定的,是一个等差数列啊,那怎么办。" 巨响不断,荷取有些失落,但依然在敲着键盘。
围观的鬼们显得有些疲惫了,为了让荷取记录下这些伤害信息,每两轮攻击之间都要等好久。
但是,没有一只鬼在抱怨。
"等等,等差?"
...
...
... "这不就是固定了伤害的增量?" 荷取仿佛看到了希望。
"那样的话,之前应对固定伤害的办法或许就有用了。"
"只要用另一个 A 序列记录下伤害的增量对其之后伤害的影响就可以了。
对 A 序列求前缀和,就可以得到刚才的那个 S 序列。
那么,这个 A 序列可以说是差分序列的差分序列。"
"对了,除了考虑增量还要考虑初始值,那么用 B 序列记录初始伤害和结束伤害,最后 加进 S 序列就行。"
"这个问题好像解决了?"
... 妖怪之山,山脚下。
荷取和同伴正在瀑布边玩耍。
虽然已经入夜,但距离深夜还早,荷取的愿望实现了。
啊不过,时间真的不早了,我们的地底旅行还要继续。
咦,这个方法,不正好可以用来解决山女的连环病原体难题吗?
真是意外的收获呢,回去的时候记得告诉山女~ 那么,接下来是,地灵殿?