形式
形如
dp[i]=max(dp[j]−a[i]×b[j]+c[j])+d[i]
的dp方程
(
a[x],b[x],c[x],d[x]为一些与x有关的式子)
(需保证b[x]满足单调性)
如果是min,则后面的过程反过来,自己理解去。
思路
为了O(1)选出最优的j,假设dp[j]优于dp[k],且b[j]>b[k]
即,
dp[j]−a[i]×b[j]+c[j]>dp[k]−a[i]×b[k]+c[k]
变成
(dp[j]+c[j])−(dp[k]+c[k])b[j]−b[k]>a[i]
所以要求
(dp[j]+c[j])−(dp[k]+c[k])b[j]−b[k] 斜率越大越好,用单调队列维护
把上面那个
b[j]当做横坐标,
(dp[j]+c[j])当做纵坐标。
维护的单调队列要使斜率要递减(保证前面的更大),画成图像就成了一个上凸包:
实现
对于一个新的i,保证b[i]最大,队列的左边为head,判断head与head+1的斜率,如果head+1更优,即
(dp[head+1]+c[head+1])−(dp[head]+c[head])b[head+1]−b[head]>a[i]
那么就
head++;
所以
dp[i]就从head位置转移过来。
接下来把
dp[i]添加进单调队列,把队尾tail斜率比i小的全部弹出去,即
(dp[i]+c[i])−(dp[tail]+c[tail])b[i]−b[tail]>(dp[tail]+c[tail])−(dp[tail−1]+c[tail−1])b[tail]−b[tail−1]
那么就
tail--;
最后把i放进tail里。