[CF311B]Cats Transport

Cats Transport

题解

很水的一道斜率优化呀

首先因为每只猫玩的位置与玩的时间是一定的,故可以将其转化为铲*官带走猫所需要的出发时间。

于是,我们将其排序后得到的单调不下降序列上截取p个点,当做其的出发时间。

dp_{i,j}为铲*官已有i人出发,第i人在刚好可以带走第j只猫的时间出发时猫们最小的出发时间,容易得到转移方程式:

dp_{i,j}=min\left \{ dp_{i-1,k}+t_{i}(j-k)-\sum_{p=k+1}^{j}t_{p} \right \}。用前缀和将t表示出来,dp_{i,j}=min\left \{ dp_{i-1,k}+t_{i}(j-k)-sum_{j}+sum_{k}\right \}

时间复杂度O\left( m^{2}p \right ),明显会T,思考优化。

当对于点i,点j比点k更优时

dp_{j}+t_{i}(i-j)+sum_{j}-sum_{i}<dp_{k}+t_{i}(i-k)+sum_{k}-sum_{i}

dp_{j}-t_{i}j+sum_{j}<dp_{k}-t_{i}k+sum_{k}

dp_{j}-dp_{k}+sum_{j}-sum_{k}<t_{i}(j-k)

\frac{dp_{j}-dp_{k}+sum_{j}-sum_{k}}{j-k}<t_{i}

又转化成了熟悉的斜率优化的格式,于是,用单调队列维护斜率即可。

时间复杂度O\left(m(p+log_{m}) \right )(有个排序),可以过。

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
typedef long long LL;
typedef pair<int,int> pii;
const LL mo=1e9+7;
const LL INF=0x7f7f7f7f;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
LL n,m,p,d[MAXN],t[MAXN],dp[105][MAXN],sum[MAXN];
LL head[105],tail[105],q[105][MAXN];
double slope(int t,LL k,LL j){return 1.0*(dp[t][k]-dp[t][j]+sum[k]-sum[j])/(k-j);}
signed main(){
	scanf("%lld %lld %lld\n",&n,&m,&p);
	for(int i=2;i<=n;i++)scanf("%lld",&d[i]),d[i]+=d[i-1];
	for(int i=1;i<=m;i++){
		int pos;scanf("%lld %lld",&pos,&t[i]);
		t[i]=t[i]-d[pos];
	}
	if(p>=m){puts("0");return 0;}
	sort(t+1,t+m+1);dp[0][0]=0;
	for(int i=1;i<=m;i++)sum[i]=sum[i-1]+t[i];
	for(int j=1;j<=m;j++)
		for(int i=1;i<=min(1ll*j,p);i++){
			while(head[i-1]+1<tail[i-1]&&slope(i-1,q[i-1][head[i-1]],q[i-1][head[i-1]+1])<=t[j])head[i-1]++;
			int k=q[i-1][head[i-1]];dp[i][j]=dp[i-1][k]+1ll*t[j]*(j-k)-sum[j]+sum[k];
			//printf("%d %d %d:%lld\n",i,j,q[head],dp[i&1][j]);
			while(head[i]+1<tail[i]&&slope(i,q[i][tail[i]-2],q[i][tail[i]-1])>slope(i,q[i][tail[i]-1],j))tail[i]--;
			q[i][tail[i]++]=j;
			/*for(int k=0;k<j;k++)
				dp[i][j]=min(dp[i][j],dp[i-1][k]+(j-k)*t[j]-(sum[j]-sum[k]));*/
		}
	printf("%lld",dp[p][m]);
	return 0;
}

谢谢!!!

posted @ 2021-10-26 23:17  StaroForgin  阅读(9)  评论(0)    收藏  举报  来源