Codeforces 801C Voltage Keepsake

题目大意

给你n个设备和一个充电器,充电器每秒可以充p个单位的电。每个设备(a,b)表示一开始有b的电量,每秒耗电a。充电器可以在任意时刻给任意一个设备充电,问你最多多少秒之后,有一个设备电量为0.(这个最多秒数不一定为整数)

题解

先分析一下题目,问你保证所有设备都能有电的最长时间,那么我们可以想到每台设备如果不充电,会耗电b/a秒。
(I)
假设全部用电器能够永远正常工作,当且仅当 p>=Σmi=1a[i] 。这种情况下输出-1.
(II)
①所以我们按照b/a从小到大拍序。然后看看这些设备能够最多撑多久。
假设现在前m个设备,那么耗电 S=Σmi=1a[i]
②假设我们能够撑到第m+1个设备电量为0前,那么我们就可以继续撑下去。我们设用前m个设备还能够继续撑下去 x 秒。能够撑下去,当且仅当 x>(tm+1tm) ,现在有一个用电量 po ,则 x=po/(Sp)
③假设我们撑不下去了,那么答案显然为 tm+x
(III)
如果不能够永远正常工作,但是能够撑到所有n个设备充电,那么显然还能够撑 po/[(Σmi=1a[i])p] 秒。最后答案就是 tn+po/[(Σmi=1a[i])p] (显然)。

收获

①这题我个人认为是个贪心,因为它将尽可能多的用电器一起撑,关键是局部解能够反映到最优解。这道题目我们可以画一个解的时间轴:
Codeforces 801C Voltage Keepsake_第1张图片
可以看出局部解反映到最优解。
②为什么我们一定要先给前面的设备充电呢?(尽管这问题很IQ↓~~~~)因为如果你给后面的充,那么前面的设备会先没电,直接影响答案。这个东西的本质其实就是告诉我们在平时解题的时候要分析条件,什么东西影响了答案,在不影响答案的情况下尽量让答案更优。

代码

#include
#include
#include
#include
#define N 100005
#define DB double
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note
{
    DB tm;
    int a,b;
};note data[N];
DB tm,ans,sum,po,p,tmdis,x;
int i,j,k,l,n,m,t;
bool cmp(note x,note y){return x.tmint main()
{
    scanf("%d%lf",&n,&p);
    fo(i,1,n)
    {
        scanf("%d%d",&data[i].a,&data[i].b);
        sum+=(DB)data[i].a;
        data[i].tm=(DB)data[i].b/(DB)data[i].a;
    }
    if (p>=sum)
    {
        printf("-1");
        return 0;
    }
    sort(data+1,data+n+1,cmp);
    sum=data[1].a;
    po=data[1].tm*p;
    i=2;
    while (i<=n)
    {
        tmdis=data[i].tm-data[i-1].tm;
        if (sum-p>0)
        {
            x=po/(sum-p);
            if (x<=tmdis)
            {
                printf("%.10lf",x+data[i-1].tm);
                break;
            }
        }
        po+=tmdis*(p-sum);
        sum+=data[i].a;
        i++;
    }
    if (i==n+1)
    {
        x=po/(sum-p);
        printf("%.10lf",x+data[n].tm);
    }
    return 0;
}

你可能感兴趣的:(Codeforces 801C Voltage Keepsake)