Codeforces 1132D - Stressful Training - [二分+贪心+优先队列]

题目连接:https://codeforces.com/contest/1132/problem/Dnode

 

题意:ios

有 $n$ 个学生,他们的电脑有初始电量 $a[1 \sim n]$,他们的电脑每分钟会耗电 $b[1 \sim n]$,如今有一场比赛持续 $k$ 分钟。c++

要你买一个充电器,使得每一个学生的电脑在比赛期间的任什么时候候的电量都不会低于 $0$(能够等于 $0$),你要求出这个充电器每分钟充电量最少是多少。spa

 

题解:code

看到这种题目,应当条件反射想到二分。blog

假设咱们如今知道充电器每分钟的充电量是 $x$,那么如何确保比赛可以进行呢?排序

一台电脑的初始电量为 $a$,耗电量为 $b$,若是不充电的话,显然在 $\lfloor \frac{a}{b} \rfloor+1$ 这一分钟是最后一分钟了,再下一分钟就负电量了。队列

因此,咱们找到这个 $\lfloor \frac{a}{b} \rfloor$ 最小的电脑,这是最快用完电的那台电脑,咱们应当优先给他充电。ci

因此在当前这一分钟,咱们选择给它冲一分钟的电,很重要的一个思想,咱们此时不维护每一个电脑的当前电量,而是在初始电量上直接加上 $x$,由于这两个操做是等价的。get

而后在下一分钟,咱们继续找此时最快会没电的电脑,继续给它充一分钟的电。

这样一来,对于一个 $x$ 进行check的时间复杂度是 $O((k+n)\log n)$,而二分 $x$ 的范围是 $[0,k \cdot \max_{i=1}^{n}(b_i)]$,记 $L = k \cdot \max_{i=1}^{n}(b_i)$。因此总时间复杂度是 $O(\log L \cdot (k+n) \cdot \log n)$。

 

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;

int n,k;
ll a[maxn],b[maxn];

struct Qnode{
    ll a,b;
    ll r;
    bool operator<(const Qnode& oth)const {
        return r>oth.r;
    }
};

inline bool check(ll x)
{
    priority_queue<Qnode> Q;
    for(int i=1;i<=n;i++) Q.push((Qnode){a[i],b[i],a[i]/b[i]});
    for(int t=1;t<=k;t++)
    {
        Qnode q=Q.top(); Q.pop();
        if(q.a/q.b+1ll<t) return 0;
        if(q.a/q.b+1ll>=k) return 1;
        Q.push((Qnode){q.a+x,q.b,(q.a+x)/q.b});
    }
    return 1;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    ll bmax=0;
    for(int i=1;i<=n;i++) cin>>b[i], bmax=max(b[i],bmax);

    ll l=0, r=(k-1)*bmax+1;
    while(l<r)
    {
        ll mid=(l+r)>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    if(l>=(k-1)*bmax+1) cout<<-1<<'\n';
    else cout<<l<<'\n';
}

 

注意,这个题还有一个点,就是优先队列里的元素,咱们按照 $a/b$ 来排序,须要开一个变量 $r = a / b$ 来减小六十四位除法的次数,来加快比较速度,不然会TLE。

相关文章
相关标签/搜索