codeforces 832c #425 DIV.2

题目链接
二分答案,对时间进行二分,假设每得到的时间是x,那么就以该时间来判断是否可以,满足条件
判断方法:
对于时间x,指定的某个人算出这个人要跑到终点,那么炸弹应该放置的区间,这样把所有向左跑的人区间算出来,然后同样的算出向右的人的区间,如果这些区间有整点重合(因为炸弹只能放在整点),那么就是满足的二分的右区间减小,反之亦然。
这里处理区间可以使用扫描线,对左端点的对应的数组值加一,右端点减一,然后左到右扫描就可以了
这里要注意几个坑点,代码中已经注释

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cstring>
#define clear(x) memset(x,0,sizeof(x))
using namespace std;
#define LL long long
struct node{
    int pos;
    double v;
    int dir;
};
node dat[100005];
int n;
double bs;
int one[1000005];
int two[1000005];
bool Judge(double t)
{
    int sl,sr;
    sl = 1e6;
    sr = 0;
    clear(one);
    clear(two);
    for(int i = 0;i<n;i++)
    {
        int pos = dat[i].pos;
        int v = dat[i].v;
        if(dat[i].dir==1)
        {
            if(v*t>=pos || (LL)v * (LL)t>=pos)
            {
                one[0]++;
                one[1000000+1]--;
                sl = 0;
                sr = 1e6;
                continue;
            }
            if((v+bs)<pos/t)
                continue;
            double t1 = (pos-t * v)/bs;
            int r;
            if(bs>1000000/t) // 因为有可能这里bs乘t爆范围 double 所以要提前判断 不然挂在42组
                r = 1000000;
            else
                r = bs * t + t1 * v;
            r = min(1000000,r);
            if(sr<r)sr = r;
            if(sl>pos)sl = pos;
            one[pos]++;
            one[r+1]--;
            //cout << "RR:" << pos << r+1 << endl;
        }
        else
        {
            pos = 1e6-pos;
            if(v*t>=pos || (LL)v * (LL)t>=pos)
            {
                two[0]++;
                two[1000000+1]--;
                sl = 0;
                sr = 1e6;
                continue;
            }
            if((v+bs)<pos/t)continue;
            double t1 = (pos-t*v)/bs;
            int l ;
            if(t>1e6/bs)  // 因为有可能这里bs乘t爆范围 double 所以要提前判断 不然挂在42组
                l = 0;
            else
                l = 1e6-floor(t*bs+t1*v); // 这里要向下取整,因为是反过来的
            l = max(0,l);
            if(sl>l)sl = l;
            if(sr<1e6-pos)sr = 1e6-pos;
            two[l]++,two[1000000-pos+1]--;

        }

    }
    int cnt1 = 0;
    int cnt2 = 0;
    for(int i = sl;i<=sr;i++)
    {
        cnt1 += one[i];
        cnt2 += two[i];
        if(cnt1>0 && cnt2>0)return true;
    }
    return false;
}
double binAns(double s,double e)
{
    double mid;
    for(int i = 0;i<50;i++)
    {
        mid = (s+e)/2;
       // cout << s << " " << e << " " << mid << endl;
        if(Judge(mid))
        {
            e = mid;
        }
        else s = mid;
    }
    return mid;
}
int main()
{
  while(scanf("%d%lf",&n,&bs)!=EOF)
    {
         for(int i = 0;i<n;i++)
        {
            scanf("%d%lf%d",&dat[i].pos,&dat[i].v,&dat[i].dir);
        }
        double ans = binAns(0,1e6);
        printf("%.10lf\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值