ShengHuaOJ 1162百度车

P5017[NOIP2018 普及组]摆渡车

ShengHuaOJ:http://47.108.137.150/problem.php?id=1162

洛谷:[NOIP2018 普及组] 摆渡车 - 洛谷

题目描述

有 n 名同学要乘坐摆渡车从人大附中前往人民大学,第 i 位同学在第 ti 分钟去 等车。只有一辆摆渡车在工作,但摆渡车容量可以视为无限大。摆渡车从人大附中出发、 把车上的同学送到人民大学、再回到人大附中(去接其他同学),这样往返一趟总共花费 m 分钟(同学上下车时间忽略不计)。摆渡车要将所有同学都送到人民大学。

凯凯很好奇,如果他能任意安排摆渡车出发的时间,那么这些同学的等车时间之和最小为多少呢?

注意:摆渡车回到人大附中后可以即刻出发

输入格式

第一行包含两个正整数 n, m 以一个空格分开,分别代表等车人数和摆渡车往返一趟的时间。
第二行包含 nn 个正整数,相邻两数之间以一个空格分隔,第 i 个非负整数 ti​ 代表第 i 个同学到达车站的时刻。

输出格式

输出一行,一个整数,表示所有同学等车时间之和的最小值(单位:分钟)。

输入输出样例

输入 #1

5 1 
3 4 4 3 5 

输出 #1

0

输入 #2

5 5 
11 13 1 5 5 

输出 #2

4

说明/提示

【输入输出样例 1 说明】

同学 1 和同学 4 在第 3 分钟开始等车,等待 0 分钟,在第 3 分钟乘坐摆渡车出发。摆渡车在第 4 分钟回到人大附中。
同学 2 和同学 3 在第 4 分钟开始等车,等待 0 分钟,在第 4 分钟乘坐摆渡车 出发。摆渡车在第 5 分钟回到人大附中。
同学 5 在第 5 分钟开始等车,等待 0 分钟,在第 5 分钟乘坐摆渡车出发。自此 所有同学都被送到人民大学。总等待时间为 0。

【输入输出样例 2 说明】

同学 3 在第 1 分钟开始等车,等待 0 分钟,在第 1 分钟乘坐摆渡车出发。摆渡 车在第 6 分钟回到人大附中。
同学 4 和同学 5 在第 5 分钟开始等车,等待 1 分钟,在第 6 分钟乘坐摆渡车 出发。摆渡车在第 1 分钟回到人大附中。
同学 1 在第 11 分钟开始等车,等待 2 分钟;同学 2 在第 13 分钟开始等车, 等待 0 分钟。他/她们在第 13 分钟乘坐摆渡车出发。自此所有同学都被送到人民大学。 总等待时间为 4。
可以证明,没有总等待时间小于 4 的方案。

【数据规模与约定对于 10\%10% 的数据,n ≤ 10, m = 1, 0 ≤ t_i ≤ 100。
对于 30\%30% 的数据,n ≤ 20, m ≤ 2, 0 ≤ t_i ≤ 100。
对于 50\%50% 的数据,n ≤ 500, m ≤ 100, 0 ≤ t_i ≤ 10^4。
另有 20\%20% 的数据,n ≤ 500, m ≤ 10, 0 ≤ t_i ≤ 4 × 10^6。
对于 100\%100% 的数据,n ≤ 500, m ≤ 100, 0 ≤ t_i ≤ 4 ×10^6。

我的理解:

  • 我发现,maxt的范围实在是太大了,有足足4000000,而此时我们注意到,n和m的却只有500和100,与4000000的差距太大了,我想到,如果两个人的时间相差得太远了,远得司机师傅早早送完了前面的所有人,却喝了几壶茶才等到了下一个人,那我们其实可以让后面的人早点到(免得司机拿工资不干事)
  • 那这个太远了是多少呢,答案是2m,不是m(这是之前一个纠结了我1个小时的问题)
  • 为什么呢,我们假设在m-1的时刻有inf个人坐车,m的时刻有一个人坐车,这时候的最优解当然是让m-1个人先坐车走,这样的话,在m时刻的人在2m-1时刻才能做到车,如果有一个人在第3m时刻坐车,将他的时间改为2m的话就会影响结果
    (上方j的上届为maxt+m而不是maxt也是这个道理)
    所以大概思路就出来了,这道题就过了
  • 代码:
#include<bits/stdc++.h>
#define ll long long
#define MAXN 1001
#define inf 0x7fffffff/2
#define N 510
#define M 110
using namespace std;
int f[2][N*M*10];
int n,m;
int t[N],minn[N*M*10];
int maxt,subt;
int flag;
int main(){
	scanf("%d %d",&n,&m);
	for(register int i=1;i<=n;i++)scanf("%d",&t[i]);
	sort(t+1,t+n+1);
	subt=t[1];
	for(register int i=1;i<=n;i++){
		t[i]-=subt;
		if(t[i]-t[i-1]>2*m){
			subt+=(t[i]-t[i-1]-2*m);
			t[i]=t[i-1]+2*m;
		}
	}
	maxt=t[n];
	memset(minn,127,sizeof(minn));
	for(register int i=0;i<=maxt+m;i++){
		f[0][i]=i,
		minn[i]=0;
	}
	for(register int i=2;i<=n;i++){
		for(register int j=0;j<=maxt+m;j++){
			f[1][j]=inf;
		}
		for(register int j=t[i];j<=maxt+m;j++){
			f[1][j]=min(f[1][j],f[0][j]+j-t[i]);
		}
		for(register int j=max(t[i],m);j<=maxt+m;j++){
			f[1][j]=min(f[1][j],minn[j-m]+j-t[i]);
		}
		for(register int j=0;j<=maxt+m;j++){
			f[0][j]=f[1][j];
		}
		for(register int j=0;j<=maxt+m;j++){
			if(!j){
				minn[j]=f[0][j];
			}else{
				minn[j]=min(minn[j-1],f[0][j]);
			}
		}
	}
	int ans=inf;
	for(register int j=0;j<=maxt+m;j++){
		ans=min(ans,f[0][j]);
	}
	printf("%d\n",ans);
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值