Cats Transport

https://loj.ac/problem/10187

题目描述

  一条路上有\(N\)座山,有\(P\)位饲养员在\(1\)号山,每只猫获取\(H_i\)号山玩到\(T_i\)时刻,求饲养员何时出发可以使所有猫的等待时间最短。

思路

  我们考虑一下先直接求出恰好接到每只猫的时刻\(a_i\),那么我们贪心的考虑,每个管理员一定会带走按\(a\)排序后一段的猫,所以我们将猫分为批次,令\(f[i][j]\)表示前\(i\)个饲养员带走\(j\)只猫的最少等待时间。那么

\[f[i][j]=min\{f[i-1][k]-\sum_{p=k}^ja[p]-a[k]\} \]

  用前缀和优化后转移方程为

\[f[i][j]=min\{f[i-1][k]+a[j]*(j-k)-s[j]+s[k]\} \]

  我们把它化为有关\(j\)的一次函数

\[f[i-1][k]+s[k]=a[j]*k-a[j]*j+s[j]+f[i][j] \]

  这样我们就把就\(f[i][j]\)的最小值转化为求截距的最小值,直接斜率优化即可。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+10;
ll q[N],f[110][N],sumd[N],s[N],a[N],g[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;
}

int main()
{
	ll n,m,p;
	n=read();m=read();p=read();
	for(ll i=2;i<=n;i++)
		sumd[i]=sumd[i-1]+read();
	for(ll i=1;i<=m;i++)
	{
		ll h=read(),t=read();
		a[i]=t-sumd[h];
	}
	sort(a+1,a+m+1);
	for(ll i=1;i<=m;i++)
		s[i]=s[i-1]+a[i];
	memset(f,0x3f,sizeof(f));
	f[0][0]=0;
	ll l=0,r=0;
	for(ll i=1;i<=p;i++)
	{
		for(ll j=1;j<=m;j++)
			g[j]=f[i-1][j]+s[j];
		l=0,r=0;q[0]=0;
		for(ll j=1;j<=m;j++)
		{
			while(l<r&&g[q[l+1]]-g[q[l]]<a[j]*(q[l+1]-q[l]))l++;
			f[i][j]=g[q[l]]+(j-q[l])*a[j]-s[j];
			while(l<r&&(g[q[r]]-g[q[r-1]])*(j-q[r])>=(g[j]-g[q[r]])*(q[r]-q[r-1]))r--;
			q[++r]=j;
		}
	}
	printf("%lld",f[p][m]);
}
posted @ 2019-11-13 21:12  fbz  阅读(206)  评论(0编辑  收藏  举报