CF311B Cats Transport 题解 Link Solve
Solve
这道题和2018的摆渡车有点像
对于每只猫,我们预处理出应该什么从(H_1)出发才刚好接到,设(A_i=T_i-sum^{H_i}_{j=1} D-j)
把(A_i)从大到小排序后就很像摆渡车了
设(F[i][j])表示前(i)个铲屎官带走了前(j)个猫,的时间总和最小,(S_i)表示(A_i)的前缀和
容易写出转移方程,第(i)个铲屎官带走从(k+1)到(j)只猫
[F[i][j]=min{(F[i-1][k]+A_j ast (j-k)-(S_j-S_k))}
]
这届枚举的事件复杂度是(O(PM^2))的,考虑优化
把狮子转化成(kx+b)的形式
[A_j ast k+(F[i][j]-A_j ast j+S_j)=S_k+F[i-1][k]
]
我们这里把(i)看成常量,把(j)看成状态变量,把(k)是决策变量
发现(A_j)是递增的,(k)也是递增的,直接单调队列维护就好了
#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
typedef long long LL;
LL D[maxn],S_D[maxn],A[maxn],S_A[maxn],DP[105][maxn],N,M,P,H[maxn],T[maxn],hed=1,til=0,ans;
int i,Q[maxn],j;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
inline LL X(LL j){return j;}
inline LL Y(LL j){return S_A[j]+DP[i-1][j];}
inline long double calc(int i,int j){return (long double)(Y(j)-Y(i))/(X(j)-X(i));}
int main(){
freopen("CF311B.in","r",stdin);
freopen("CF311B.out","w",stdout);
N=read();M=read();P=read();
for(i=2;i<=N;i++)D[i]=read(),S_D[i]=S_D[i-1]+D[i];
for(i=1;i<=M;i++)H[i]=read(),T[i]=read();
for(i=1;i<=M;i++)A[i]=T[i]-S_D[H[i]];
sort(A+1,A+1+M);
for(i=1;i<=M;i++)S_A[i]=S_A[i-1]+A[i];
for(j=1;j<=M;j++)DP[1][j]=A[j]*j-S_A[j];
ans=DP[1][M];
for(i=2;i<=P;i++){
hed=1,til=0;Q[++til]=0;
for(j=1;j<=M;j++){
while(hed<til&&calc(Q[hed+1],Q[hed])<=A[j])++hed;
int k=Q[hed];
DP[i][j]=DP[i-1][k]+A[j]*(j-k)-(S_A[j]-S_A[k]);
while(hed<til&&calc(Q[til],Q[til-1])>=calc(Q[til-1],j))--til;
Q[++til]=j;
}
ans=min(ans,DP[i][M]);
}
printf("%lld
",ans);
return 0;
}