包裹快递
题目描述
小 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<n≤10。
- 对于 30 % 30\% 30% 的数据, 0 < x i , y i , s i ≤ 1000 0<x_i,y_i,s_i \le 1000 0<xi,yi,si≤1000。
- 对于 50 % 50\% 50% 的数据, 0 < n ≤ 1000 0<n \le 1000 0<n≤1000。
- 对于 100 % 100\% 100% 的数据, 0 < n ≤ 2 × 1 0 5 0<n \le 2\times10^5 0<n≤2×105, x i ≤ y i ≤ 1 0 8 x_i \le y_i \le 10^8 xi≤yi≤108, s i ≤ 1 0 7 s_i \le10^7 si≤107。
样例解释
第一段用 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的值