sequence_单调队列, connon_DP

来源:互联网 发布:淘宝助理打印模板在哪 编辑:程序博客网 时间:2024/05/29 19:02


1 sequence 

给出n个二元对(ai, bi),从中确定最长不下降子串,其中位置i的值可以为ai到bi的任意一个。(通俗的讲就是,每个位置都可定一个值,介于ai与bi之间,再找出这个串的最长不下降子串)。 n<=10^6


<GREEDY>

这道题首先可以用贪心求解,从每个位置推下去就可以了。 fi= max(f i-1, a[i])  {fi-1 <= b[i]}


<ADVANCED>

我用的是维护一个指针p,顺序枚举i, 从位置p到位置i这串是可行的, 并且维护f数组。若枚举到了一个j,发现 fj-1> bj , 我们可以调整i,使得fj-1下降, 再看看是否可行。

所以我们记录一个d数组, di= fi- ai。

那我们很直观的是使 p = Pos of Min( Dx) +1 {p<=x<j},这样可以使得fj-1下降 r , r= Min (Dy) {p‘<=y<j}  p'是新的p

通俗一点讲呢, d数组是每个数的f值还可以下降多少, 那么 Min(Dx){p<=x<j} 就是整串 p~j-1都可下降的数目(因为这是不下降子序列,下降必须整串下降)。

下降完了之后, 那么Min(Dx)这个位置呢,就卡住了这个序列(变成了0)。

若现在下降了的fj-1还大于bj, 那么我就要把p调整到 这个位置 之后, 这样后面的fj-1才可以继续下降。

所以现在的操作成了

1. 下降

2. 判断 fj-1 与 bj 的大小关系, 若bj大, 那么 跳出, 否则继续

3. 调整位置p,若无位置可转了,那么跳出。

4. 转1

所以总体实现两个操作: 1 找出当前序列的最小值   2把某个位置之前的数全部删除

所以用单调队列实现。


2 connon

给出不上升的数列(N个数)hi,和M种操作,每种操作可以使不大于ai的数减去di(减去以后小于0的视为0), 为k次操作,可以使多少数变为0,并求此情况下剩余几次操作。

N<=250000, m<=500, di<=500, ai与数列中的数均小于10^18.

首先给出最直接的做法。

消除每一个数都有一个总次数, 而且若A>B, 那么B的消除次数不比A的大。

那么我们做一次Dp, Fi为消除i这个数需要多少次。 Fi = Fi-x +1 {x为所有操作中 ai大于等于i 的中 最大 的di}

时间复杂度O(mlogm + max(hi)).

正解只是加了一点东西。首先我们把无用的操作去除掉之后共组成了S个区间, 每个区间的x值是确定的(x为Dp方程中)。

 对于Fp, 若属于R区间, 那么 Fp= Fp-k*x + k   {p-k*x<= R-1区间的ai值}, 看做进行了k次操作。

注意di<=500, 所以 p-k*x 与 a[R-1]必定差小于500.

所以对于每个区间预处理500个f值就可以了。 


原创粉丝点击