任务安排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;
}