Codeforces 801C Voltage Keepsake

  1.因为充电器在任意时刻给任意机器充电,并且交换充电对象并不消耗时间,所以可以从整体来看,如果充电器每秒可以冲的电量p大于等于全部机器的每秒消耗的电量的话,相当于可以利用充电器做到,让每台机器的电量始终大于等于它的原电量,也就是每台机器电量只可能增不可能减,所以可以无限使用下去。2.若不能无限的使用下去的话,因为使用的时间越长,出现某个机器电量为0的概率就越大可以理解为1111000000(1代表可以使用到该时刻,0代表不能使用到该时刻)可以看出具有单调性,那就通过二分求出能使用的最长时间。二分的话主要就是要考虑check函数,按每个机器不充电能使用到的最大时间排个序,然后依次取到mid时刻,详细的见注释。

#include<bits/stdc++.h>
using namespace std;
#define eps 1e-7
struct node
{
    double a,b,time;
}ma[1000000+10];
double p;
int n;
bool cmp(const node&a,const node&b)
{
    return a.time<b.time;
}
bool check(double mid)
{
    double tmp=0;
    for(int i=0;i<n;i++)
    {
        if(ma[i].time>mid) break;
        tmp+=(mid-ma[i].time)*ma[i].a;//因为要判断能不能使用到mid时刻,所以要把在mid时刻之前就没电的机器充上电才行,这步操作是计算给这些没电了的机器充电需要消耗的电量。
    }
    return mid*p>=tmp;若充电器能提供的电量>=需要的电量则mid满足
}
int  main()
{
    double tmp=0;
    cin>>n>>p;
    for(int i=0;i<n;i++)
    {
        cin>>ma[i].a>>ma[i].b;
        ma[i].time=ma[i].b/ma[i].a;
        tmp+=ma[i].a;

    }
    if(p>=tmp)
    {
        cout<<-1<<endl;
        return 0;
    }
    sort(ma,ma+n,cmp);
    double low=0,up=1e11+100,mid;//这个上限我一开始开小了,过不了,看了别人的就改大过了
    while(up-low>=eps)
    {
        mid=(low+up)/2;
        if(check(mid))
            low=mid;
        else
            up=mid;
    }
    printf("%.10lf\n",low);
    return 0;
}

 

posted @ 2018-08-18 14:48  eason99  阅读(79)  评论(0编辑  收藏  举报