越快越好!
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
假期将至,潘警长打算带n个实习步行出去巡逻,他们正通过一条长l米的通道。每个见习的速度恒定为v1米每秒。
为了尽快通过这条通道,大家向总部请求了一辆巡逻车。巡逻车可以载k个人(即一次不能运超过k个人)而且速度恒定为v2米每秒。
因为吃苦耐劳是我们的传统,所以每个人只能乘一次巡逻车。
现在请求出所有人通过通道的最小时间,忽略上下车的时间和车子掉头的时间。
什么?你问我警长算不算?他开车呢,故不计入上述n和k中。
Input
输入包含多组数据(组数不超过50),每组数据仅一行五个整数n,l,v1,v2和k,含义见题目描述。
变量满足如下约定:1<=n<=10000,1<=l<=10^9,1<=v1<v2<=10^9,1<=k<=n
Output
一个实数表示最小时间,要求与答案的相对误差在10-6以内。
Sample input and output
Sample Input | Sample Output |
---|---|
5 10 1 2 5 3 6 1 2 1 |
5.0000000000 4.7142857143 |
Hint
by litter_star
Source
2017 UESTC Training for Math
解题思路:我们首先二分答案,我们可以发现,每个人走的路分为两种,一种是他自己步行,一种是他坐车,显然最优解肯定是每个人的坐车时间和步行时间
一样(每个人坐车情况一样,不要误认为坐车的时间和步行时间一样都为总时间的1/2),既然这样那么判断一个时间是否合法,直接模拟一遍就行,因为一旦总时间确定,我们可以计算出坐车的时间和步行的时间,最后有一点要注意车也要回到终点,刚开始没有注意到这个,wa了无数发。
#include <bits/stdc++.h> using namespace std; int n, k; double l, v1, v2; double eps = 1e-6; bool judge(double mid) { double x = (v1 * v2 * mid - v2 * l) / (v1 - v2); double t1 = x / v2; double t2 = (x - v1 * t1) / (v1 + v2); double x1 = x - v2 * t2; double now = 0; double sum = 0; if(n % k == 0) { int num = n / k; sum = (double)num * (t1 + t2); sum -= t2; now += (num - 1) * x1; now += x; } else { int num = n / k; sum = (double) num * (t1 + t2); sum += t1; now += num * x1; now += x; } if(sum - mid > eps) return false; double dd = mid - sum; now += dd * v2; if(now - l >= eps) return true; else return false; } int main() { while(~scanf("%d%lf%lf%lf%d", &n, &l, &v1, &v2, &k)) { double L = l / v2; double R = l / v1; while(R - L > eps) { double mid = (L + R) / 2.0; if(judge(mid)) { R = mid; } else { L = mid; } } printf("%.10lf\n", L); } return 0; }