ICPC2020上海D - Walker
三分 or 分类讨论
[D-Walker_第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海)(重现赛)@hzy0227 (nowcoder.com)](https://codeforces.com/gym/103202/problem/I)
题意
有 10000 组测试数据
每组给出 5 个浮点数 \(n,p_0,v_0,p_1,v_1\), 分别表示线段长度,第一个人初始位置和速度,第二个人的初始位置和速度
两个人的运动方向可以随始改变,求这两个人的轨迹能把整个线段覆盖掉的最短时间
思路
-
可以在 \([p_0,p_1]\) 中间三分一个位置 \(mid\), 让 \([0,mid]\) 归第一个人覆盖,\([mid,n]\) 归第二个人覆盖,解决两个子问题即可
-
特判一种情况:第一个人一直向右到 n,第二个人一直向左到 0;与三分的最小值取 min 即可
代码
#include<bits/stdc++.h>
typedef long long ll;
typedef std::pair<int, int> PII;
#define ALL(x) x.begin(),x.end()
#define pb push_back
#define fi first
#define se second
#define double long double
using namespace std;
const double eps = 1e-10;
inline ll _read() {
static ll ans;
static unsigned int c;
static bool p;
for (c = getchar(); c != '-' && (c < '0' || c > '9'); c = getchar());
if (c == '-') p = false, c = getchar(); else p = true;
for (ans = 0; c <= '9' && c >= '0'; c = getchar()) ans = ans * 10 + c - '0';
return p ? ans :-ans;
}
double n;
double p[2], v[2];
int sgn(double x)
{
if (abs(x) < eps)
return 0;
if (x > eps)
return 1;
return -1;
}
double f(double x)
{
return max((min(x - p[0], p[0]) + x) / v[0], (min(p[1] - x, n - p[1]) + n - x) / v[1]);
}
int main() {
int T;
scanf("%d", &T);
while(T--)
{
scanf("%Lf%Lf%Lf%Lf%Lf", &n, &p[0], &v[0], &p[1], &v[1]);
int cnt = 1500;
if (p[0] > p[1]) swap(p[0], p[1]), swap(v[0], v[1]);
double l = p[0], r = p[1];
double ans = min(f(l), f(r));
while(cnt--)
{
double midl = l + (r - l) / 3;
double midr = r - (r - l) / 3;
double fl = f(midl), fr = f(midr);
if (sgn(fl - fr) == -1)
r = midr;
else
l = midl;
ans = min(ans, min(fl, fr));
}
ans = min((n + min(p[0], n - p[0])) / v[0], ans);
ans = min((n + min(p[1], n - p[1])) / v[1], ans);
double tmp = max((n - p[0]) / v[0], p[1] / v[1]);
ans = min(ans, tmp);
printf("%.12Lf\n", ans);
}
return 0;
}