题目大意:你正在参加一个障碍滑雪比赛,由山头滑向山脚。途中必须经过若干宽度为W的门。你的横向移动速度是已知的。现在给定若干滑雪板,他们有不同的垂直速度,请你选择一款滑雪板,使得能够最快的完成比赛。
将滑雪板按速度排序之后进行二分。由于一开始可以站在任意点,所以第一个门范围内的任意点我们都是可以到达的,然后计算到达下一个门的时间,再根据横向移动速度,可以计算出到达下一个门时,我们能到达的范围区间,这个区间和下一个门交的部分,就是我们可以达到的部分。如果这个交集是空集,就说明这块滑雪板太快了,没有足够的时间进行横向移动。
将滑雪板按速度排序之后进行二分。由于一开始可以站在任意点,所以第一个门范围内的任意点我们都是可以到达的,然后计算到达下一个门的时间,再根据横向移动速度,可以计算出到达下一个门时,我们能到达的范围区间,这个区间和下一个门交的部分,就是我们可以达到的部分。如果这个交集是空集,就说明这块滑雪板太快了,没有足够的时间进行横向移动。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int W,vh,N;
int xs[100000],ys[100000];
int S;
int ss[1000000];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&W,&vh,&N);
for(int i=0; i<N; i++)
{
scanf("%d%d",&xs[i],&ys[i]);
}
scanf("%d",&S);
for(int i=0; i<S; i++)
{
scanf("%d",&ss[i]);
}
sort(&ss[0], &ss[S]);
int lo = -1, hi = S;
while (lo+1 < hi)
{
int mid = (lo+hi)/2;
long long s = ss[mid];
/*从最顶端的开始扫,由于第一个位置可以是门的任意位置,
所以l,r分别是第一个位置的左右两边 */
double l = xs[N-1]+0.0, r = xs[N-1]+W+0.0 ;
long long y = ys[N-1];
bool ok = 1;
/*从第二个位置开始扫,可以到达的左右两边,
(以左端点往左走,右端点往右走)
通过比例式子:vh/vy=x位移/y位移
所以可以到达的距离就是l-左边的 r+右边的
*/
for(int i=N-2; i>=0; i--)
{
l -= ((double)vh*(y-ys[i]))/(double)s;
r += ((double)vh*(y-ys[i]))/(double)s;
/*如果超出下一次的门的范围只要取门的任意范围就好了*/
if(l<xs[i]) l = xs[i];
if(r>(xs[i]+W)) r = (xs[i]+W);
//如果不与门相交,即空集的情况说明速度大了,下次要往左边速度扫描
if (r < l)
{
ok = 0;
break;
}
y = ys[i];
}
if (ok) lo = mid;
else hi = mid;
}
if (lo==-1)
{
printf("IMPOSSIBLE\n");
}
else
{
printf("%d\n", ss[lo]);
}
}
return 0;
}