题解 P2365 【任务安排】

算法:斜率优化动态规划

由于题解里没有关于的斜率优化做法,我打算写一下这种特殊的斜率优化动态规划

由于可以小于零,所以斜率不具有单调性,所以我们不能像原来一样维护下凸壳。我们不能只保留相邻两点斜率大于的部分,我们要把整个下凸壳都保留下来。这时队首也就不是最优解了,要二分找到一个左边比小,右边比大的位置。这个位置就是答案

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=500005;
int l,r,n,s,t,c,j,sumt[N],sumc[N],f[N],q[N];
int find(int k)//二分查找左边比$s+sumt[i]$小,右边比$s+sumt[i]$大的位置
{
    if(l==r)return q[l];
    int L=l,R=r;
    while(L<R)
    {
        int mid=(L+R)/2;
        if(f[q[mid+1]]-f[q[mid]]<=k*(sumc[q[mid+1]]-sumc[q[mid]]))L=mid+1;
        else R=mid;
    }
    return q[L];
}
signed main()
{
    scanf("%lld%lld",&n,&s);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&t,&c);
        sumt[i]=sumt[i-1]+t;
        sumc[i]=sumc[i-1]+c;
    }
    l=r=1;q[1]=0;
    for(int i=1;i<=n;i++)
    {
        int j=find(s+sumt[i]);//二分查找答案
        f[i]=f[j]+sumt[i]*(sumc[i]-sumc[j])+s*(sumc[n]-sumc[j]);
        while(l<r&&(f[q[r]]-f[q[r-1]])*(sumc[i]-sumc[q[r]])>=
        (f[i]-f[q[r]])*(sumc[q[r]]-sumc[q[r-1]]))r--;//如果不构成下凸壳,就删除队尾
        q[++r]=i;
    }
    cout<<f[n]<<endl;
}