题目链接:http://codeforces.com/contest/832/problem/C

题目大意:

  n个人,面向左或者右站在同一条轴上,每个人在轴上的坐标为x,速度为v。请你在某个位置放置一个炸弹,炸弹一炸,每个人都会立即朝前跑。炸弹会发出一道怪光,速度s,如果人被这道怪光从身后追上,那么这个人的速度就会 s+v 。请你合理放置炸弹,使得从炸弹爆炸到有人跑到0并且有人跑到1e6所需的时间最短。

解题思路:

  比赛时这道题想了一个多小时,完全没有思路,思路来源于Tutorial

  从0到1e6二分时间,判断在这个时间是否可以达成目标,具体细节请看代码和注释,因为这一题的细节有一点多。

AC代码:

 #include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn=1e5+;
double s;
int n;
struct p{
double x,v;
int t;//t,1左;2右.
}man[maxn];
bool jiao(pair<double,double>l,pair<double,double>r){
//这里是边界情况讨论,非常恶心,其实就是说:因为这里讨论的坐标点都是整数,所以对于一个区间的左端点,我们要向右取整,对于右端点则要向左取整,这样最稳妥。
double ls=floor(l.second);
double lf=ceil(l.first);
double rs=floor(r.second);
double rf=ceil(r.first);
if(ls>=rf&&lf<=rs) return true;
if(rs>=lf&&rf<=ls) return true;
return false;
}
bool can(double time){ //判断函数
//********************************************
//一开始先假设用这么多时间无法到达左右端点
bool left=false,right=false;
pair<double,double>l,r; //l和r记录如果要到达左右端,炸弹可以放置的区间
l=r=make_pair(1e6*1.0,0.0); //这个区间就代表无法到达左右端点
//*****************************************
for(int i=;i<n;i++){
double xx=man[i].x,vv=man[i].v;
//接下来这部分只分析到达左端点这一部分,到达右端点的同理
//事实上,我在打这一部分的时候是左右端判断镜像进行的,这样比较不会乱
if(man[i].t==){
if(vv*time>=xx){ //如果光靠这个人自己走就能在这个时间内到达左端点,那么炸弹放在哪里就无所谓了
left=true;
l=make_pair(0.0,1e6*1.0);
}
else if((vv+s)*time>=xx){ //这是最优的情况,炸弹直接放在这个人脚下,一炸他马上就被加速
left=true;
double t=(time*vv+time*s-xx)/s; //(1)
double maxr=xx-vv*t+s*t; //(2)
//式子(1)、(2)其实就是求炸弹最右能放到哪里,不难想到,当炸弹放在最右,这个人刚好能在规定的时间到达左端
l.first=min(l.first,xx);
l.second=max(l.second,maxr);//更新区间
}
}
else{
if(vv*time>=1e6*1.0-xx){
right=true;
r=make_pair(0.0,1e6*1.0);
}
else if((vv+s)*time>=1e6*1.0-xx){
right=true;
double t=(s*time+vv*time-1e6*1.0+xx)/s;
double maxl=xx+vv*t-s*t;
r.first=min(r.first,maxl);
r.second=max(r.second,xx);
}
}
if(left&&right&&jiao(l,r)){//能到达左右端并且l和r有交集,证明这个时间可以到达
return true;
}
}
return false;
}
int main(){
scanf("%d%lf",&n,&s);
for(int i=;i<n;i++)
scanf("%lf%lf%d",&man[i].x,&man[i].v,&man[i].t);
double l=0.0,r=1e6*1.0;
for(int i=;i<;i++){ //循环100次就足够精确了
double m=(l+r)/2.0;
if(can(m)) r=m;
else l=m;
}
printf("%.7lf\n",l);
return ;
}

  

CF832C的更多相关文章

随机推荐

  1. c语言----实战植物大战僵尸

    1. 原理 通过指针先找到阳光的地址,然后修改地址对应的值即修改阳光值. 2. 工具 CheatEngine  --- 查询进程中变量的地址 Dll注入工具  -----  注入 VS2017 3. ...

  2. visual stdio 2012快捷键

    为什么80%的码农都做不了架构师?>>>   VS2012变化的快捷键:注释::VS2010是(Ctrl+E,C),VS2012是(Ctrl+K, Ctrl+C),实际操作,按住Ct ...

  3. shell基础知识DAY2

    1.管道符(|):把一个命令的输出,把输出的内容传递给管道符后面命令的输入.如:ls -l | grep "^[^d]".2.jobs作业控制,后台运行bg PID,前台运行fg ...

  4. 手把手教你用Node.js爬虫爬取网站数据

    个人网站 https://iiter.cn 程序员导航站 开业啦,欢迎各位观众姥爷赏脸参观,如有意见或建议希望能够不吝赐教! 开始之前请先确保自己安装了Node.js环境,还没有安装的的童鞋请自行百度 ...

  5. 配置secondarynamenode主机名masters

    1.配置hadoop的secondarynamenode,配置内容如下 node2 本文转自 素颜猪 51CTO博客,原文链接:http://blog.51cto.com/suyanzhu/19592 ...

  6. 啃算法:归并排序及JavaScript实现

    在学习归并排序之前,有必要了解分治法,因为归并排序正是应用了分治模式.(基本定义摘自<算法导论>) 一.分治法 1.思想: 将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些 ...

  7. Node Mysql事务处理封装

    node回调函数的方式使得数据库事务貌似并没有像java.php那样编写简单,网上找了一些事务处理的封装并没有达到自己预期的那样简单编写,还是自己封装一个吧.封装的大体思路很简单:函数接受一个事务处理 ...

  8. 数论--HDU 1495 非常可乐

    Description 大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为.因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和se ...

  9. codeforce 1311 D. Three Integers

    In one move, you can add +1 or −1 to any of these integers (i.e. increase or decrease any number by ...

  10. zabbix分布式安装全过程

    项目规划 软件 版本 IP zabbix-server 3.4.15 10.1.10.128 zabbix-proxy 3.4.15 10.1.10.129 zabbix-agent 3.4.15 1 ...