斜率优化DP

斜率优化DP

题外话

考试的时候被这个玩意弄得瑟瑟发抖
大概是yybGG的Day4
小蒟蒻表示根本不会做…..
然后自己默默地搞了一下斜率优化

这里算是开始吗??

其实我讲的会非常非常非常简单,,,而且绝对没有一张图(因为我绘图水平太菜)
貌似没太多友善的题目可以用来搞….算了
虚一点,缥缈一点的来说吧….

其实我就是写给自己看的…

对于某一类DP方程形如:(当然max也可以)

f[i]=min(f[j]+g(i,j))

其中 g(i,j)
是一个只和i于j相关的函数
我们知道
转移一定是从某个位置转移过来了,其他位置的转移一定不会比这个位置好
所以,不妨设从j位置转移过来,另外一个奇怪的位置从k转一个过来

于是有:

f[j]+g(i,j)<f[k]+g(i,k)

接下来再假设一步
我们假设 g(i,j)=h(i)t(j)
其中 h(i) t(j) 是只和i与j有关的函数
那么不等式变为
f[j]+h(i)t(j)<f[k]+h(i)t(k)

移项得
h(i)(t(j)t(k))<f[k]f[j]

h(i)<f[k]f[j]t(j)t(k)

这个时候就看到右边的东西没有???
但是要记住,除过去可能会要变号
这玩意就可以视作一个斜率啦

但是,这个玩意有了不能够直接用嗷
只有当满足单调的时候才能够用斜率优化
当且仅当 h(i)f[i]t(i)
都要满足单调的时候才能够用(根据取max或min,符号等单调性有所不同)
这个时候,利用单调队列维护一个凸包就可以啦
具体的类似代码如下:

for(int i=1;i<=n;++i)
    {
        while(head1])<=h[i])Head++;
        int get=Q[head];
        f[i]=f[get]+Calc(i,get);
        while(head1],Q[tail])>=count(Q[tail],i))tail--;
        Q[++tail]=i;
    }

这是一份比较伪的代码
第一个while循环,目的是弹出队列头位置的不合法的状态(因为 h(i) 的值在变化)
中间的两句话是转移,可以直接利用斜率优化 O(1) 转移
后面那个while循环目的是维护单调性,当前的节点如果放进来会破坏队尾的单调性,所以要进行调整
最后一个是加入队尾,继续进行操作
这样子的话就可以维护斜率进行斜率优化啦


接下来是几道题目

有待补充
【BZOJ1010】【HNOI2008】玩具装箱
【BZOJ1911】【APIO2010】特别行动队
【Luogu2900】土地征用
【BZOJ1096】【ZJOI2007】仓库建设

你可能感兴趣的:(======总结======,斜率优化)