【洛谷 P5017】 摆渡车(斜率优化)

题目链接
算是巩固了一下斜率优化吧。
\(f[i]\)表示前\(i\)分钟最少等待时间。
则有\(f[i]=\min_{j=0}^{i-m}f[j]+(cnt[i]-cnt[j])*i-(sum[i]-sum[j])\)
其中\(cnt[i]\)\(sum[i]\)分别表示前\(i\)分钟去等车的学生数量和他们去等车的时刻之和。
变形一下得\(f[j]+sum[j]=i*cnt[j]+i*cnt[i]-sum[i]-f[i]\)
维护一个下凸包即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 510;
const int MAXT = 4000010;
int n, m, t[MAXN], cnt[MAXT], sum[MAXT], f[MAXT], ans = 2147483647, q[MAXT], head, tail;
inline double k(int i, int j){
	return (double)(f[j] + sum[j] - f[i] - sum[i]) / (cnt[i] == cnt[j] ? 1e-9 : cnt[j] - cnt[i]);
}
int main(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i){
		scanf("%d", &t[i]);
		cnt[t[i]]++;
		sum[t[i]] += t[i]; 
	}
	sort(t + 1, t + n + 1);
	for(int i = 0; i < t[n] + m; ++i)
		cnt[i] += cnt[i - 1], sum[i] += sum[i - 1];
	for(int i = 0; i < m; ++i)
		f[i] = cnt[i] * i - sum[i];
	for(int i = m; i < t[n] + m; ++i){
		while(head < tail && k(q[tail - 1], q[tail]) >= k(q[tail], i - m)) --tail;
		q[++tail] = i - m;
		while(head < tail && k(q[head], q[head + 1]) <= i) ++head;
		int j = q[head];
		f[i] = f[j] + (cnt[i] - cnt[j]) * i - (sum[i] - sum[j]);
		if(i >= t[n]) ans = min(ans, f[i]);
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2019-10-03 22:06  Qihoo360  阅读(230)  评论(0编辑  收藏  举报
You're powerful!