[SDOI2012]任务安排

解析

预算费用,和Luogu P2365 任务安排一样
得到了同样的式子
但是我们发现 (sumt_i) 可能小于零
也就是说我们需要的斜率可能不再具有单调性
所以我们要维护整个凸壳
那么怎么找到最佳的决策点呢?
其实就是 (slope(m,m-1) < sumt_i)(slope(m,m+1) >= sumt_i) 中的 (m)
于是我们可以二分整个凸壳,找到这样的点
也就是判断等价于 (slope(m , m + 1) >= sumt_i)
满足这个不等式的决策可能成为最有决策,记录下来
然后我们要找凸壳中更靠前的,于是 (r=mid-1)

(Code)

#include<cstdio>
using namespace std;
typedef long long LL;

const int N = 3e5 + 5;
int n , q[N];
LL f[N] , T[N] , C[N] , s , t , c;

double slope(int u , int v)
{
	if (C[u] == C[v]) return 1.0 / 0.0;
	return 1.0 * ((f[u] - s * C[u]) - (f[v] - s * C[v])) / (1.0 * C[u] - C[v]);
}

int search(int l , int r , int m)
{
	if (l == r) return q[l];
	int mid , res = r;
	while (l <= r)
	{
		mid = (l + r) >> 1;
		if (slope(q[mid] , q[mid + 1]) >= m) res = mid , r = mid - 1;
		else l = mid + 1;
	}
	return q[res];
}

int main()
{
	scanf("%d%lld" , &n , &s);
	for(register int i = 1; i <= n; i++)  
		scanf("%lld%lld" , &t , &c) , T[i] = T[i - 1] + t , C[i] = C[i - 1] + c;
	int r;
	q[r = 1] = 0;
	for(register int i = 1; i <= n; i++)
	{
		int j = search(1 , r , T[i]);
		f[i] = f[j] + T[i] * (C[i] - C[j]) + s * (C[n] - C[j]);
		while (r > 1 && slope(i , q[r]) < slope(q[r] , q[r - 1])) --r;
		q[++r] = i;
	}
	printf("%lld" , f[n]);
} 
原文地址:https://www.cnblogs.com/leiyuanze/p/13680969.html