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\), 分别表示线段长度,第一个人初始位置和速度,第二个人的初始位置和速度

两个人的运动方向可以随始改变,求这两个人的轨迹能把整个线段覆盖掉的最短时间

思路

  1. 可以在 \([p_0,p_1]\) 中间三分一个位置 \(mid\), 让 \([0,mid]\) 归第一个人覆盖,\([mid,n]\) 归第二个人覆盖,解决两个子问题即可

  2. 特判一种情况:第一个人一直向右到 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;
}
posted @ 2022-10-05 13:23  hzy0227  阅读(37)  评论(0编辑  收藏  举报