luogu P5017 摆渡车 斜率dp

参考博客:https://www.luogu.com.cn/blog/Sooke/solution-p5017

//把各个点映射到数轴上
//然后 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 4000105;
int n, m, t, ti, ans = 1e9;
int cnt[N], sum[N], q[N], f[N];
double getSlope(int u, int v)
{
	return (double)(f[v] + sum[v] - f[u] - sum[u]) / (cnt[u] == cnt[v] ? 1e-9 : cnt[v] - cnt[u]);
}
int main()
{
	cin >> n >> m;
	for(int i=1; i <= n; i++)
	{
		cin >> ti;
		ti ++;
		t = max(t, ti);
		//人数++
		cnt[ti] ++;
		//对应到数轴上
		sum[ti] += ti;
	}
	for(int i = 1; i < t + m; i ++)
	{
		cnt[i] += cnt[i - 1];    // 前缀和.
		sum[i] += sum[i - 1];
	}
	int hh = 0, tt = 0;
	for(int i = 1; i <= t + m; i++)
	{
		if(i > m)
		{
			while(hh < tt && getSlope(q[tt - 1], q[tt]) >= getSlope(q[tt], i - m))
				tt --;
			q[++ tt] = i - m; // 把可能成为最优解的推入队列.
		}
		while(hh < tt && getSlope(q[hh], q[hh + 1]) <= i)
			hh ++;   // 把不可能成为最优解的弹出队列.
		f[i] = cnt[i] * i - sum[i]; // 特判边界情况.
		if(hh <= tt)
			f[i] =min(f[i], f[q[hh]] + (cnt[i] - cnt[q[hh]]) * i - (sum[i] - sum[q[hh]]));    // 斜率优化转移.
	}
	for(int i = t; i < t + m; i++)
		ans = min(ans, f[i]);
	cout << ans << endl;
	return 0;
}
posted @ 2020-04-25 12:50  晴屿  阅读(97)  评论(0编辑  收藏  举报