Codeforces 801C Voltage Keepsake

原题传送

题意:n个设备同时使用,第i个设备每秒消耗ai个单位的电,开始时有bi个单位的电。有一个充电器,每秒充p个单位的电,每次只能充一个设备,充电时间可以为任意的实数,且假设不需要时间更换充电设备。问这n个设备中直到存在一个电量为0个单位的设备时最多能用多长时间。如果能用无限长的时间,输出-1。


一开始先把所有设备的a加起来,即a1+a2+……+an,把算出的结果与p比较,若p>= a1+a2+……+an,则能用无限长的时间,输出-1。

如果不能用无限长的时间,我们假设充电器充到了一个充电宝里,这个充电宝能充无限的电量,充电宝能充无限个设备,而当前充电宝的电量为pow。把所有设备在不充电时能用的时间算出来(这里假设第i个设备能用ti秒)再进行升序排序,然后让时间短的设备先充电,让这些设备能用更长的时间。这里设需要充电的设备为1~m,sum=a1+a2+……+a,充电后让时间延长至tm+1(前提是有足够的电量维持,此时pow+(tm+1 -tm )*>= (tm+1 -tm)*sum,如果不能让时间延长至tm+1,算出他们最多能延长到的时间(设为tmax),这个时间就是答案。

还有一种情况,就是电量足以延长至tn,此时就延长所有设备的使用时间至最大值,这个时间就是答案。关键是怎么求tmax呢?= tmax-tmtmax= tm+x,故:



Codeforces 801C Voltage Keepsake_第1张图片


下面用数据来解释一下吧:

第一组数据:

2 1
2 2
2 1000
首先求: a 1 + a 2+……+ an =4,而p=1<4= a 1+ a 2+……+ an ,因此不能用无限长的时间。

把所有设备在不充电时能用的时间算出来:

第一个设备能用2/2=1s,t1=1s, a1=2

第二个设备能用1000/2=500s,t2=500s,  a2=2

排序后:

t1=1s, a1=2

t2=500s,  a2=2

此时充电宝电力为pow=t1*p=1

先充第1个设备(m=1),此时sum=a1=2,由于pow + (t2 -t1< (t2 -t1)*sum,所以不能让时间延长至t2,x=pow/(sum-p)=1/1=1s,故tmax= tm+x=1+1=2s

所以答案为:2


再看第二组数据:

1 100
1 1
首先求: a 1+ a 2+……+ an =1,而p=100>1= a 1+ a 2+……+ an ,因此能用无限长的时间。输出-1 。


再看第三组数据:

3 5
4 3
5 2
6 1
首先求: a 1+ a 2+……+ an=15,而p=5<15= a 1+ a 2+……+ an ,因此不能用无限长的时间。

把所有设备在不充电时能用的时间算出来:

第一个设备能用3/4=0.75s,t1=0.75s, a1=4

第二个设备能用2/5=0.4s,t2=0.4s, a2=5

第三个设备能用6/1=0.166666666666667s,t3=0.166666666666667s, a3=6


排序后:

t1=0.166666666666667s, a1=6

t2=0.4s, a2=5

t3=0.75s, a3=4


此时充电宝电力为pow=t1*p=0.833333333333333

先充第1个设备(m=1),此时sum=a1=6,由于pow + (t2 -t1) * p > (t2 -t1)*sum ,所以能让时间延长至t2

此时pow=pow(原来的电量)+(tm+1 -tm)*p(这段时间充的电量)- (tm+1 -tm)*sum(让设备1用的时间延长至t2所耗的电量)

               =pow+ (tm+1 -tm)*(sum-p)

故pow=0.833333333333333+(0.4-0.166666666666667)*(5-6)= 0.6

接着充1-2两个设备(m=2),此时sum=a1+a2=11,由于pow + (t3 -t2) * p < (t3 -t2)*sum,所以不能让时间延长至t3

此时x=pow/(sum-p)=0.6/6=0.1s

tmax= t2+x=0.4+0.1=0.5s



附上代码:

#include 
using namespace std;
struct In{
    long long a;
    double t;
}s[100005];
bool cmp(In p, In q) {
    return p.t < q.t;
}
int main() {
    long long n, p, mid;
    scanf("%lld%lld", &n, &p);
    long long sum1 = 0;
    for(long long i = 0; i < n; i++) {
        scanf("%lld%lld", &s[i].a, &mid);
        sum1 += s[i].a;
        s[i].t = mid * 1.0 / s[i].a;
    }
    if(sum1 <= p)
        printf("-1\n");
    else {
        sort(s, s + n, cmp);
        double time = s[0].t;
        double pow = s[0].t * p;
        double dis, x;
        long long sum = s[0].a;
        long long i = 1;
        while(i < n) {
            dis = s[i].t - time;
            if(sum > p) {
                x = pow / (sum - p);
                if(x <= dis) {
                    printf("%.10f\n", time + x);
                    break;
                }
            }
            pow = pow + dis * (p - sum);
            sum += s[i].a;
            time = s[i].t;
            i++;
        }
        if(i == n) {
            x = pow / (sum - p);
            printf("%.10f\n", time + x);
        }
    }
    return 0;
}




你可能感兴趣的:(Codeforces)