HDU3045 Picnic Cows

题面

HDU

vjudge

题解

将权值排序,则分组一定是连续的

设$f[i]$表示前$i$头牛的最小代价,则($a[i]$为$i$的权值):

$$ f[i] = f[j - 1] + sum[i] - sum[j - 1] - (i - j + 1) * a[j] $$

套上斜率优化的板子即可。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define RG register
#define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
#define clear(x, y) memset(x, y, sizeof(x))

const int maxn(5e5 + 10);
int n, t, q[maxn];
long long sum[maxn], a[maxn], f[maxn];
inline long long x(int i) { return a[i]; }
inline long long y(int i) { return f[i - 1] - sum[i - 1] + (i - 1) * a[i]; }

inline bool check(int i, int j, int k)
{
	return (y(i) - y(j)) * (x(j) - x(k)) <= (y(j) - y(k)) * (x(i) - x(j));
}

int main()
{
	while(~scanf("%d%d", &n, &t))
	{
		for(RG int i = 1; i <= n; i++) scanf("%lld", a + i);
		std::sort(a + 1, a + n + 1);
		for(RG int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
		int S = t << 1, head = 1, tail = 0;
		for(RG int i = t; i < S; i++) f[i] = sum[i] - i * a[1];
		for(RG int i = S; i <= n; i++)
		{
			while(head < tail && check(i - t + 1, q[tail], q[tail - 1])) --tail;
			q[++tail] = i - t + 1;
			while(head < tail && (y(q[head + 1]) - y(q[head]))
					<= (x(q[head + 1]) - x(q[head])) * i) ++head;
			f[i] = f[q[head] - 1] + sum[i] - sum[q[head] - 1] -
				(i - q[head] + 1) * a[q[head]];
		}
		printf("%lld\n", f[n]);
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/cj-xxz/p/10220207.html