• CF832C


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

    题目大意:

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

    解题思路:

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

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

    AC代码:

     1 #include <algorithm>
     2 #include <cstdio>
     3 #include <cmath>
     4 using namespace std;
     5 const int maxn=1e5+5;
     6 double s;
     7 int n;
     8 struct p{
     9     double x,v;
    10     int t;//t,1左;2右.
    11 }man[maxn];
    12 bool jiao(pair<double,double>l,pair<double,double>r){
    13 //这里是边界情况讨论,非常恶心,其实就是说:因为这里讨论的坐标点都是整数,所以对于一个区间的左端点,我们要向右取整,对于右端点则要向左取整,这样最稳妥。
    14     double ls=floor(l.second);
    15     double lf=ceil(l.first);
    16     double rs=floor(r.second);
    17     double rf=ceil(r.first);
    18     if(ls>=rf&&lf<=rs)    return true;
    19     if(rs>=lf&&rf<=ls)   return true;
    20     return false;
    21 }
    22 bool can(double time){          //判断函数
    23 //********************************************
    24 //一开始先假设用这么多时间无法到达左右端点
    25     bool left=false,right=false;
    26     pair<double,double>l,r;     //l和r记录如果要到达左右端,炸弹可以放置的区间
    27     l=r=make_pair(1e6*1.0,0.0); //这个区间就代表无法到达左右端点
    28 //*****************************************
    29     for(int i=0;i<n;i++){
    30         double xx=man[i].x,vv=man[i].v;
    31 //接下来这部分只分析到达左端点这一部分,到达右端点的同理
    32 //事实上,我在打这一部分的时候是左右端判断镜像进行的,这样比较不会乱
    33         if(man[i].t==1){
    34             if(vv*time>=xx){    //如果光靠这个人自己走就能在这个时间内到达左端点,那么炸弹放在哪里就无所谓了
    35                 left=true;
    36                 l=make_pair(0.0,1e6*1.0);
    37             }
    38             else if((vv+s)*time>=xx){   //这是最优的情况,炸弹直接放在这个人脚下,一炸他马上就被加速
    39                 left=true;
    40                 double t=(time*vv+time*s-xx)/s; //(1)
    41                 double maxr=xx-vv*t+s*t;        //(2)
    42 //式子(1)、(2)其实就是求炸弹最右能放到哪里,不难想到,当炸弹放在最右,这个人刚好能在规定的时间到达左端
    43                 l.first=min(l.first,xx);
    44                 l.second=max(l.second,maxr);//更新区间
    45             }
    46         }
    47         else{
    48             if(vv*time>=1e6*1.0-xx){
    49                 right=true;
    50                 r=make_pair(0.0,1e6*1.0);
    51             }
    52             else if((vv+s)*time>=1e6*1.0-xx){
    53                 right=true;
    54                 double t=(s*time+vv*time-1e6*1.0+xx)/s;
    55                 double maxl=xx+vv*t-s*t;
    56                 r.first=min(r.first,maxl);
    57                 r.second=max(r.second,xx);
    58             }
    59         }
    60         if(left&&right&&jiao(l,r)){//能到达左右端并且l和r有交集,证明这个时间可以到达
    61             return true;
    62         }
    63     }
    64     return false;
    65 }
    66 int main(){
    67     scanf("%d%lf",&n,&s);
    68     for(int i=0;i<n;i++)
    69         scanf("%lf%lf%d",&man[i].x,&man[i].v,&man[i].t);
    70     double l=0.0,r=1e6*1.0;
    71     for(int i=0;i<100;i++){     //循环100次就足够精确了
    72         double m=(l+r)/2.0;
    73         if(can(m))  r=m;
    74         else    l=m;
    75     }
    76     printf("%.7lf
    ",l);
    77     return 0;
    78 }

      

    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    数据库内外连接以及自然连接
    Mybatis的一级二级缓存
    彻底弄懂CAS单点登录
    Tomcat部署项目的方式
    redis集群脑裂以及解决方案
    AOP分析--代理方式的选择
    线程池
    数据结构--结构体
    Python程序--选择判断
    C语言--密码问题
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/7348507.html
Copyright © 2020-2023  润新知