CF311B Cats Transport

XVII.CF311B Cats Transport

推式子时间到~~~

我们首先对题目中的di做前缀和,求出每座山距离原点距离;

然后对于第i只猫,如果一个饲养员在tidhi时刻以后出发就可以接到它;

注意,饲养员可以在负时刻就出发!!!我之前想多了以为只能在非负时刻出发而纳闷了好半天

我们设tidhi为新的ti,然后将所有的ti排序。

然后开始DP:

f[i][j]表示:前i只猫,派出j个人,的最优时间。再设si表示ti的前缀和。

则有f[i][j]=mink=0i1{f[k][j1]+ti(ik)(sisk)}

我们这样就可以写出O(m2p)的代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,p,d[100100],t[100100],s[100100],f[100100][110],qwq=0x3f3f3f3f3f3f3f3f;
signed main(){
	scanf("%lld%lld%lld",&n,&m,&p),memset(f,0x3f3f3f3f,sizeof(f));
	for(int i=2;i<=n;i++)scanf("%lld",&d[i]),d[i]+=d[i-1];
//	for(int i=1;i<=n;i++)printf("%lld ",d[i]);puts("");
	for(int i=1,x,y;i<=m;i++)scanf("%lld%lld",&x,&y),t[i]=y-d[x];
//	printf("%lld\n",res);
//	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
	sort(t+1,t+m+1);
	for(int i=1;i<=m;i++)s[i]=s[i-1]+t[i];
//	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
	f[0][0]=0;
	for(int j=1;j<=p;j++)for(int i=1;i<=m;i++)for(int k=0;k<i;k++)f[i][j]=min(f[i][j],f[k][j-1]+(i-k)*t[i]-(s[i]-s[k]));
	for(int i=1;i<=p;i++)qwq=min(qwq,f[m][i]);
	printf("%lld\n",qwq);
	return 0;
}

然后考虑斜率优化一下:

f[i][j]中,我们按照列优先(先枚举j)的顺序进行DP;并且,设f[i][j1]F[i]

j<k<i(不是同一个j)。则如果jk优,则有:

Fj+ti(ij)(sisj)<Fk+ti(ik)(sisk)

拆开

Fj+itijtisi+sj<Fk+itiktisisk

抵消

Fjjti+sj<Fkkti+sk

移项

FjFk+sjsk<(jk)ti

除过去(注意jk是负数)

FjFk+sjskjk>ti

右边的ti是递增的(排过序了),因此可以采用单调队列维护斜率;然后维护一个下凸壳即可。复杂度O(mp)

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,p,d[100100],t[100100],s[100100],f[100100][110],qwq=0x3f3f3f3f3f3f3f3f,l,r,q[100100];
signed main(){
	scanf("%lld%lld%lld",&n,&m,&p),memset(f,0x3f3f3f3f,sizeof(f));
	for(int i=2;i<=n;i++)scanf("%lld",&d[i]),d[i]+=d[i-1];
//	for(int i=1;i<=n;i++)printf("%lld ",d[i]);puts("");
	for(int i=1,x,y;i<=m;i++)scanf("%lld%lld",&x,&y),t[i]=y-d[x];
//	printf("%lld\n",res);
//	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
	sort(t+1,t+m+1);
	for(int i=1;i<=m;i++)s[i]=s[i-1]+t[i];
//	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
	f[0][0]=0;
	for(int j=1;j<=p;j++){
		l=r=0;
		for(int i=1;i<=m;i++){
			while(r-l&&(f[q[l]][j-1]-f[q[l+1]][j-1]+s[q[l]]-s[q[l+1]])>=(q[l]-q[l+1])*t[i])l++;
			f[i][j]=f[q[l]][j-1]+(i-q[l])*t[i]-(s[i]-s[q[l]]);
			while(r-l&&(f[q[r-1]][j-1]-f[q[r]][j-1]+s[q[r-1]]-s[q[r]])*(q[r]-i)>=(f[q[r]][j-1]-f[i][j-1]+s[q[r]]-s[i])*(q[r-1]-q[r]))r--;
			q[++r]=i;
		}
	}
	for(int i=1;i<=p;i++)qwq=min(qwq,f[m][i]);
	printf("%lld\n",qwq);
	return 0;
}

posted @   Troverld  阅读(48)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示