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]);
}