dp斜率规划

斜率规划:dp式子转移时候取min/max时会从多个以有状态转移而来,斜率优化可以从一次函数的角度来排除无用的情况,从而对dp式子进行优化

例题1​​​​​​

 

每次枚举分组点j,对于每个分组点,后面的所有都会加上一个空余时间

用tsum和wsum分别表示t与w的前缀和

则有:

dp[i]=min_{j=0}^{j<i}(dp[j]+b*(wsum[a]-wsum[j])+tsum[i]*(wsum[i]-wsum[j])))

式子时间复杂度为O(n^2)

 dp[0]=0;
    for(int i=1;i<=a;i++){
        for(int j=0;j<i;j++){
            dp[i]=min(dp[i],dp[j]+tsum[i]*(wsum[i]-wsum[j])+(wsum[a]-wsum[j])*b);
        }
    }

例题2 

来回看dp式子,去掉min,则有

dp[i]=dp[j]+b*(wsum[a]-wsum[j])+tsum[i]*(wsum[i]-wsum[j])

因为j是变量,所有把式子看成一次函数的式子

dp[j]=(b+tsum[i])*wsum[j]+dp[i]-wsum[i]*tsum[i]-b*wsum[a] 

这里令y=dp[j], k=(b+tsum[i]), x=wsum[j], b=dp[i]-wsum[i]*tsum[i]-b*wsum[a]

发现b中除了dp[i]以外都是定值,则容易发现只需求出来b的最小值

那么用单调队列保存凸包

  push_back(0);
    for(int i=1;i<=a;i++){
        while(!empty()&&(dp[q[l+1]]-dp[q[l]])<=(b+tsum[i])*(wsum[q[l+1]]-wsum[q[l]])) pop_front();//相邻两个点的k值如果小于需要的k,那么这个点一定不是最优的
        dp[i]=dp[q[l]]-(b+tsum[i])*wsum[q[l]]+b*wsum[a]+tsum[i]*wsum[i];
        while(!empty()&&(dp[i]-dp[q[r]])*(wsum[q[r]]-wsum[q[r-1]])<=(dp[q[r]]-dp[q[r-1]])*(wsum[i]-wsum[q[r]])) pop_back();//维护凸包
        push_back(i);
    }

 例题3

因为时间有正有负,所以dp数组没有单调性

但是仍有一个性质:一个点若为所求的点,那么这个点左边的线段斜率k1,右边线段斜率k2,有

k1<k<k2

那么可以用二分求解

int binary_search(ll x){
    int l1=l,r1=r,ans=0;
    while(l1<=r1){
        int mid=(l1+r1)/2;
        if(dp[q[mid+1]]-dp[q[mid]]>=x*(wsum[q[mid+1]]-wsum[q[mid]])){
            ans=r1;
            r1=mid-1;
        }else{
            l1=mid+1;
        }
    }
    return l1;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值