P1542 包裹快递

包裹快递

题目描述

小 K 成功地破解了密文。但是乘车到 X 国的时候,发现钱包被偷了,于是无奈之下只好作快递员来攒足路费去 Orz 教主……

一个快递公司要将 n n n 个包裹分别送到 n n n 个地方,并分配给邮递员小 K 一个事先设定好的路线,小 K 需要开车按照路线给的地点顺序相继送达,且不能遗漏一个地点。小 K 得到每个地方可以签收的时间段,并且也知道路线中一个地方到下一个地方的距离。若到达某一个地方的时间早于可以签收的时间段,则必须在这个地方停留至可以签收,但不能晚于签收的时间段,可以认为签收的过程是瞬间完成的。

为了节省燃料,小 K 希望在全部送达的情况下,车的最大速度越小越好,就找到了你给他设计一种方案,并求出车的最大速度最小是多少。

输入格式

第 1 行为一个正整数 n n n,表示需要运送包裹的地点数。

下面 n n n 行,第 i + 1 i+1 i+1 行有 3 个正整数 x i , y i , s i x _ i, y _ i, s _ i xi,yi,si,表示按路线顺序给出第 i i i 个地点签收包裹的时间段为 [ x i , y i ] [x _ i, y _ i] [xi,yi],即最早为距出发时刻 x i x _ i xi,最晚为距出发时刻 y i y _ i yi,从前一个地点到达第 i i i 个地点距离为 s i s _ i si,且保证路线中 x i x _ i xi 递增。

可以认为 s 1 s _ 1 s1 为出发的地方到第 1 1 1 个地点的距离,且出发时刻为 0 0 0

输出格式

仅包括一个正数,为车的最大速度最小值,结果保留两位小数。

样例 #1

样例输入 #1

3
1 2 2
6 6 2
7 8 4

样例输出 #1

2.00

提示

数据范围
  • 对于 20 % 20\% 20% 的数据, 0 < n ≤ 10 0 < n \le 10 0<n10
  • 对于 30 % 30\% 30% 的数据, 0 < x i , y i , s i ≤ 1000 0<x_i,y_i,s_i \le 1000 0<xi,yi,si1000
  • 对于 50 % 50\% 50% 的数据, 0 < n ≤ 1000 0<n \le 1000 0<n1000
  • 对于 100 % 100\% 100% 的数据, 0 < n ≤ 2 × 1 0 5 0<n \le 2\times10^5 0<n2×105 x i ≤ y i ≤ 1 0 8 x_i \le y_i \le 10^8 xiyi108 s i ≤ 1 0 7 s_i \le10^7 si107

样例解释

第一段用 1 1 1 的速度在时间 2 2 2 到达第 1 1 1 个地点,第二段用 0.5 0.5 0.5 的速度在时间 6 6 6 到达第 2 2 2 个地点,第三段用 2 2 2 的速度在时间 8 8 8 到达第 3 3 3 个地点。

分析

二分答案,只需要考虑check函数的写法

代码

#include <bits/stdc++.h>
using namespace std;
const int M=1e6;
int n;
int x[M],y[M],s[M];

long double ans=0;
void read() {
	cin>>n;
	for (int i=1;i<=n;i++) cin>>x[i]>>y[i]>>s[i];	
}
bool check(long double d){
	long double sum=0.0;
	for (int i=1;i<=n;i++){
		sum+=s[i]/d;
		if (sum>y[i]) return false;
		if (sum<x[i]) sum=x[i];
	}
	return true;
}
long double solve(){
	long double l=0,r=1e9;
	while(r-l>=1e-9){
		long double mid=(l+r)/2.0;
		if (check(mid)) ans=mid,r=mid;
		else l=mid;
	}
	return ans;
}
int main() {
	read();
	printf("%.2Lf",solve());
	return 0;
}

分析

先说明,此题数据范围极大,应使用long double进行计算

bool check(long double d){
	long double sum=0.0;
	for (int i=1;i<=n;i++){
		sum+=s[i]/d;
		if (sum>y[i]) return false;
		if (sum<x[i]) sum=x[i];
	}
	return true;
}

sum表示当前时刻,或总时间。d表示二分出的速度,每次加上走一段距离的时间,此时有两种特殊情况:
1.若超时直接返回false,已经不可能完成任务
2.若比规定时间早,则需更新sum

long double solve(){
	long double l=0,r=1e9;
	while(r-l>=1e-9){
		long double mid=(l+r)/2.0;
		if (check(mid)) ans=mid,r=mid;
		else l=mid;
	}
	return ans;
}

二分答案,每次根据check来确定区间范围即可,决定改变l的值或r的值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值