任务安排 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
",f[n]);
}

原文地址:https://www.cnblogs.com/fangbozhen/p/11853083.html