*[2020上海ICPC]D. Walker(贪心+二分)

题目链接:http://codeforces.com/gym/102900/problem/D
题意:一个坐标轴[0,n]上面有两个点p1,p2,这两个点分别可以以v1,v2的速度向正方向或反方向移动,求轨迹覆盖整个坐标轴的最小时间
解题思路:
一开始想法是多分几种情况
比如:
①一个人走完全程
②两个人相对着走到端点
③两个人先向两端走,然后在中间某点回合
④两个人先往中间走,在某点会和后往两边走
但是其中第三种和第四种分别讨论的子情况太多了,一直wa在第10个样例上
参考了网上的不同的思路,发现可以直接把坐标轴分成两块,让p1和p2去走,然后二分时间来求最小时间就可以了
二分时使用贪心,求p1和p2在t时间内最大的覆盖面积
处理的时候把坐标轴分割为两个区间,分两种大情况,
第一种把左区间分给p1,右区间分给p2
solve(p1, v1, mid) + solve(n - p2, v2, mid)
第二种把右区间分给p1,左区间分给p2
solve(n - p1, v1, mid) + solve(p2, v2, mid)
当取得的覆盖区域超过n的时候即满足条件
之所以要分两种大情况,可以这么想,p1和p2位置都在[0,n/2]上,p1<p2,但是v1远大于v2,所以让p1去跑右区间比较合适
在这两种大情况下,还要分两种小情况,即先往左端点走还是先往右端点走的问题,可以看下方代码注释

double solve(double p, double v, double t) {
	//将所有情况都当成p点出发t时间
	double d = v * t;
	if (d < p)
		return 0;
	//p点出发t时间的最大覆盖面积s,即覆盖面积为[0,max(s,p)]
	//s求法有两种情况,一种是先向左走到端点0再回头,s=d-p
	//另外一种是先向右走到最大距离s,再回头走到0,s=p+(d-p)/2
	return max(p, max(d - p, p + (d - p) / 2));
}
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<math.h>
#include<string.h>
#include<string>
#include<map>
using namespace std;
#define ll long long
const double eps = 1e-8;
const int mod = 1e9 + 7;
int t;
double n, p1, v1, p2, v2;
double ans;

double solve(double p, double v, double t) {
	//将所有情况都当成p点出发t时间
	double d = v * t;
	if (d < p)
		return 0;
	//p点出发t时间的最大覆盖面积s,即覆盖面积为[0,max(s,p)]
	//s求法有两种情况,一种是先向左走到端点0再回头,s=d-p
	//另外一种是先向右走到最大距离s,再回头走到0,s=p+(d-p)/2
	return max(p, max(d - p, p + (d - p) / 2));
}
int main() {
	cin >> t;
	while (t--) {
		cin >> n >> p1 >> v1 >> p2 >> v2;
		double L = 0, R = 2e7;
		while (L +eps <= R) {
			double mid = (L + R) / 2;
			//左右区间分割
			double s1 = solve(p1, v1, mid) + solve(n - p2, v2, mid);
			//右左区间分割
			double s2 = solve(n - p1, v1, mid) + solve(p2, v2, mid);
			if (s1 >= n || s2 >= n)
				R = mid;
			else
				L = mid;
		}
		ans = L;
		printf("%.6f\n", ans);

	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Buyi.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值