Cats Transport

Cats Transport

现在有n座山,第i座山的坐标为\(d_i\),初始p个饲养员在山1,有m只猫,每只猫有一个属性\(h_i,t_i\)表示猫i
\(h_i\)以及它在\(t_i\)时间后才能被带走(\(t_i\)之前不算做在等待),现在请安排饲养员的出发时间,每个饲养员的速度都为每个单位长度每个单位时间,让所有的猫被带走之前的等待时间之和最短。

\(2<=n<=10^5,1<=m<=10^5,1<=p<=100\)

注意到饲养员的出发时间是不可能作为状态的,现在让d变为其前缀和,设一个饲养员的出发时间为t,于是考虑等待时间对于一只猫i的等待时间应为\(t+d_{h_i}-t_i\),注意到猫要能够被饲养员带走,必然有\(t+d_{h_i}\geq t_i\),也即\(t\geq t_i-d_{h_i}\),于是为了简单判断猫是否能被带走,我们应该维护一个\(g_i=t_i-d_{h_i}\),为了便于判断一个饲养员能带走哪些猫,我们自然要排序,于是现在即发现问题即哪些连续的猫被哪个饲养员带走,于是问题被转化成了任务安排。

因此设\(f[i][j]\)表示前i个饲养员,带走前j只猫的最少等待时间,设s为g的前缀和,不难有

\[f[i][j]=f[i-1][k]_{0\leq k< i}+\sum_{l=k+1}^j(g_j-g_l)\]

边界:\(f[0][0]=0\),其余无限大

经整理,它的斜率优化式应为

\[s_k+f[i-1][k]=kg_j+f[i][j]-jg_j+s_j\]

发现k是递增的,而g也是递增的,于是我们只要用单调队列维护斜率,在按斜率关系弹掉队首,答案取队首即可,时间复杂度易知\(O(np)\)

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define il inline
#define ri register
#define ll long long
#define Size 200010
using namespace std;
int T[Size];
ll d[Size],g[Size],y[Size],
    dp[101][Size],s[Size];
template<class free>il void read(free&);
int main(){
    int n,m,p,A,B;read(n),read(m),read(p);
    for(int i(2);i<=n;++i)read(d[i]),d[i]+=d[i-1];
    for(int i(1),j,k;i<=m;++i)read(j),read(k),g[i]=k-d[j];
    sort(g+1,g+m+1);for(int i(1);i<=m;++i)s[i]=s[i-1]+g[i];
    memset(dp,1,sizeof(dp)),dp[0][0]=0;
    for(int i(1),j;i<=p;++i)
        for(A=B=j=1;j<=m;++j){
            while(A<B&&g[j]*(T[A+1]-T[A])>=y[T[A+1]]-y[T[A]])++A;
            dp[i][j]=dp[i-1][T[A]]+(j-T[A])*g[j]-(s[j]-s[T[A]]),y[j]=dp[i-1][j]+s[j];
            while(A<B&&(y[T[B]]-y[T[B-1]])*(j-T[B])>=(y[j]-y[T[B]])*(T[B]-T[B-1]))--B;
            T[++B]=j;
        }printf("%lld",dp[p][m]);
    return 0;
}
template<class free>
il void read(free&x){
    x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

转载于:https://www.cnblogs.com/a1b3c7d9/p/10976397.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值