Codeforces Round # 409 C. Voltage Keepsake (二分)

时间:2022-12-19 16:50:34

题意

You have n devices that you want to use simultaneously.

The i-th device uses ai units of power per second. This usage is continuous. That is, in λ seconds, the device will use λai units of power. The i-th device currently has bi units of power stored. All devices can store an arbitrary amount of power.

You have a single charger that can plug to any single device. The charger will add p units of power per second to a device. This charging is continuous. That is, if you plug in a device for λ seconds, it will gain λ·p units of power. You can switch which device is charging at any arbitrary unit of time (including real numbers), and the time it takes to switch is negligible.

You are wondering, what is the maximum amount of time you can use the devices until one of them hits 0 units of power.

If you can use the devices indefinitely, print -1. Otherwise, print the maximum amount of time before any one device hits 0 power.

给定 n 台机器同时使用,第 i 台机器每秒消耗能量 ai ,初始能量为 bi 。有一个充电器能给 n 台机器充电,同一时间只能给一台机器充电,每秒充能量 p 。其中充电不必按整秒进行,即例如给第 1 台充 0.001 秒,给第 2 台充 0.12 秒是合法的,且不必考虑交换充电机器的时间。问 n 台机器最多能同时工作多少时间?

若 n 台机器能够无限工作,输出 -1

解题思路

当且仅当 Σaip 时,能够无限工作。

二分进行枚举能够同时工作 t 秒,再对 t 秒判断每台机器是否都能够坚持 t 秒钟。

判断 n 台机器是否能坚持至少 t 秒:在 t 秒时间充电器能够充能量总值为 pt 。枚举判断 n 台机器能否坚持 t 秒,对于能量不足的机器,从 pt 的总值中扣除不足部分。若最终 pt 仍有剩余,说明至少能坚持 t 秒,否则不能。

代码

#include<bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
int n;
double p, a[100010], b[100010];
bool jug(double t)
{
    double ext = p * 1.0 * t;
    double sub;
    for(int i=1;i<=n;i++)
    {
        sub = a[i] * t - b[i];
        if(sub > 0) ext -= sub;
        if(ext < 0) return false;
    }
    return true;
}
int main()
{
    double sum = 0;
    scanf("%d %lf",&n,&p);
    for(int i=1;i<=n;i++)
        scanf("%lf %lf",&a[i],&b[i]),   sum += a[i];
    if((p - sum) >= -eps){
        printf("-1\n");
        return 0;
    }
    double l = 0, r = 1e12, mid, ans;
    while((r-l) > eps)
    {
        mid = (l+r)/2;
        if(jug(mid))
            l = mid,  ans = mid;
        else
            r = mid;
    }
    printf("%.8lf\n", ans);
}

/*
针对这段代码可能出现在 32 位编译器中用下列样例将进入死循环的情况,可以考虑将 eps 改为 1e-6,或在 64 位编译器下运行。
原因: 32 位编译器下 double 的有效数字仅在 15 位左右。
Sample:
25000 49999
2 99999
2 99999
2 99999
...
2 99999

正统做法:由于 double 的有效位数有限以及本题答案较大,在 1e-4 的相对精度下,限制二分次数 100 次左右可以保证达到精度要求且时间较短。
*/