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。

相關文章
相關標籤/搜索