CodeForces 832C. Strange Radiation 二分

传送门

题意

在区间 \([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;
}
posted @ 2020-01-08 02:02  BakaCirno  阅读(119)  评论(0编辑  收藏  举报