CF311B Cats Transport 题解

Link

CF311B Cats Transport

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;
}
原文地址:https://www.cnblogs.com/martian148/p/14070548.html