任务安排 3
https://loj.ac/problem/10186
题目描述
同任务安排2,不过\(T\)可能为负。
思路
由于\(T\)为负,我们就无法保证前缀和的单调性,所以我们不能直接贪心的进行选择,而是要维护整个凸壳,不过我们仍然有类似的结论,对于一个点,如果它左边的线段斜率小于\(k\),右边的大于\(k\),那么它一定是最优的,所以我们可以在凸壳的单调队列中二分查找这个值。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=3e5+10;
ll f[N],sumt[N],sumc[N],q[N];
ll read()
{
ll res=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
return res*w;
}
ll search(ll r,ll k)
{
ll l=0,ans=0;
while(l<=r)
{
ll mid=l+r>>1;
if((f[q[mid+1]]-f[q[mid]])>k*(sumc[q[mid+1]]-sumc[q[mid]]))ans=mid,r=mid-1;
else l=mid+1;
}
return q[ans];
}
int main()
{
ll n=read(),s=read();
for(ll i=1;i<=n;i++)
sumt[i]=sumt[i-1]+read(),
sumc[i]=sumc[i-1]+read();
ll l=0,r=0;
for(ll i=1;i<=n;i++)
{
ll j=search(r,s+sumt[i]);
f[i]=f[j]-(s+sumt[i])*sumc[j]+sumt[i]*sumc[i]+s*sumc[n];
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<<'x'<<j<<' '<<f[i]<<endl;
}
printf("%lld\n",f[n]);
}