题意
在区间 ([0,10^6]) 内有 (n) 个人,每个人在开始时有一个位置、方向和速度 (v_i),向面对的方向移动,
你可以放一个炸弹在区间中任意整数位置,炸弹爆炸后向两边分别发射一道速度为 (s) 的波
和波同向的人接触到波之后速度会变成 (v_i+s)
问最少多少时间后左右区间都有人到达。
思路
这种问最少合法答案的题都应该往二分上想
若已知时间 (t),问题是如何验证其合法性
可以先决定一个方向,然后对于每一个朝这个方向的人,算出如果他想在 (t) 以内到达边界,
炸弹应该放置的位置,这个位置显然是一个区间,然后求出每一个人对应区间的并集
同理求出另一个方向对应炸弹可以放置的区间
如果这两个区间有交集,那么 (t) 就合法,
至于怎么计算每个人对应的区间,那就只有拿笔算一算了
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
const int MAXM=1e6+10;
const int L=1e6;
int n,s,suml[MAXM],sumr[MAXM];
struct Person{
int x,v,dir;
}p[MAXN];
bool check(double t){
memset(suml,0,sizeof(suml));
memset(sumr,0,sizeof(sumr));
for(int i=1;i<=n;i++){
int x=p[i].x,v=p[i].v,dir=p[i].dir;
if(dir==1){
if(t*v>=x+1e-8) {suml[0]++;continue;}
if(t*(s+v)<x-1e-8) continue;
double dis=(t*(s-v)*(s+v)+1.0*v*x-1.0*s*x)/s;
suml[x]++;suml[min((int)dis+x,L)+1]--;
}
else{
if(t*v>=L-x+1e-8) {sumr[0]++;continue;}
if(t*(s+v)<L-x-1e-8) continue;
double dis=(t*(s-v)*(s+v)+1.0*(L-x)*(v-s))/s;
sumr[max(x-(int)dis,0)]++;sumr[x+1]--;
}
}
for(int i=1;i<=1e6;i++) suml[i]+=suml[i-1],sumr[i]+=sumr[i-1];
for(int i=0;i<=1e6;i++) if(suml[i]&&sumr[i]) return true;
return false;
}
int main(){
scanf("%d%d",&n,&s);
for(int i=1;i<=n;i++)
scanf("%d%d%d",&p[i].x,&p[i].v,&p[i].dir);
double l=0,r=1e6;
while(r-l>1e-8){
double mid=(r+l)/2;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.7lf",l);
return 0;
}