Codeforces 500E. New Year Domino
这一题可以用在线做,但是我还没想清楚怎么维护....之前说只能离线做简直是打脸
可以用类似DP的思路,前面k-1个多米诺到第k个的决策最优,再计算从前k个多米诺到第k+1个的决策最优。
我们考虑第k-1个骨牌, 假设 len[k-1]+pos[k-1] < pos[k], 那么就肯定需要把它的高度增加 pos[k] - pos[k-1] - len[k-1]; 反之,就不用管.
接着我们考虑第k-2个个骨牌, 因为我们之前扫描过k-1了,所以现在k-2骨牌倒下后肯定能够碰到第k-1个骨牌,
然后现在有两种方法让k-2碰倒第k个,
一、k-2倒下后直接喷到k, 需要增加的长度是 temp1 = x[k] - x[k-2] - y[k-2]
二、k-2倒下后碰到k-1,k-1再倒下碰到k, 需要增加的长度是 temp2 = x[k] - x[k-1] - y[k-1](因为k-2倒下后肯定能碰到k-1)
于是我们就比较temp1和temp2,选择优的那一个.
因此我们可以从第一个骨牌扫描到最后一个骨牌。
假设现在我们扫描到了第k个骨牌,它前面肯定存在一个区间 (a1, k-1], 这个区间内的每个多米诺的最优情况都是不直接碰到k,而是先碰倒k-1,然后让k-1碰到k;
然后在(a1, k-1]这个区间前面,肯定还有一个区间(a2, a1], 这个区间每个多米诺的最优情况都是不直接碰到k,而是先碰倒a1, 然后a1碰到k;
接下来就会有(a3, a2] .... [1, ak]如此类推
对于(a1, k-1]这个区间内的所有多米诺长度, 都需要增加 max(x[k] - x[k-1] - y[k-1], 0);
对于(a2, a1 ]这个区间内的所有多米诺长度, 都需要增加 max(x[k] - x[a1] - y[a1], 0);
因此可以发现,长度增加是区间更新,所以用线段树维护多米诺骨牌的增加长度。
因为每一次都是相对于现在多米诺的最优增量(也就是最小),所以每次转移到后面的骨牌时,这些增量永远是相对更小的,因此可以不用清空,直接维护。
现在的问题就变成了怎么去找 a0(我们令a0 = k-1), a1, a2, a3 ... ak;
其实可以发现 x[ai] + y[ai] < x[a(i+1)] + y[a(i+1)] 并且 x[ai] + y[ai] >= x[j] + y[j] ( a(i+1)
然后就可以用一个单调队列来维护ai
// whn6325689
// Mr.Phoebe
// http://blog.csdn.net/u013007900
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include