任务安排2

承接上文任务安排1。
考虑优化转移。对方程变形得到 \(f_j=(s+t_i)c_j+f_i-sc_n-t_ic_i\),我们可以发现形如一个 \(y=kx+b\) 的解析式。然后我们就可以维护一个下凸包,又因为横坐标是单调的,斜率也是单调的,每次都可以把队首的一些点删掉,就是队首的斜率 \(\le\) 当前的直线斜率 \(s+t_i\),然后队尾加入新的点时,可以删除队尾斜率高于新点的。
注意从队首移除操作中的斜率也可以是 \(<\) 当前斜率,因为二者等价,两个点截距都一样。但是如果多移除肯定会更快一点。

#include<bits/stdc++.h>
using namespace std;
#define L(i,l,r) for(int i=l;i<=r;++i)
#define R(i,l,r) for(int i=r;i>=l;--i)
const int N=300010;
int n,s,c[N],t[N],q[N];
typedef long long ll;
ll f[N];
int main(){
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    // ios::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);
    scanf("%d%d",&n,&s);
    L(i, 1, n){
        scanf("%d%d",t+i,c+i);
        t[i]+=t[i-1];
        c[i]+=c[i-1];
    }
    int hh=0,tt=0;
    L(i, 1, n){
        while(hh<tt&&f[q[hh+1]]-f[q[hh]]<=1ll*(s+t[i])*(c[q[hh+1]]-c[q[hh]]))++hh;
        int j=q[hh];
        f[i]=f[j]+1ll*(c[i]-c[j])*t[i]+1ll*(c[n]-c[j])*s;
        while(hh<tt&&(__int128)(f[q[tt]]-f[q[tt-1]])*(__int128)(c[i]-c[q[tt]])>=(c[q[tt]]-c[q[tt-1]])*(f[i]-f[q[tt]]))--tt;
        q[++tt]=i;
    }
    printf("%lld",f[n]);
    return 0;
}
posted @ 2023-04-22 09:02  wscqwq  阅读(10)  评论(0编辑  收藏  举报