Stressful Training(CF1132D)
Stressful Training
https://ac.nowcoder.com/acm/problem/113525
题意
有个学生要打一场分钟的比赛。(n,k<=2e5)
每个学生的电脑有初始电量和每分钟耗电量(电量在这一分钟的最后一刻结算,即在下一分钟时才会减少,最终电量允许为负)。(ai<1e12,bi<1e7)
学生们买了一个充电器,功率为任意值,每分钟可以使电量增加。D
问题:求最小的,使所有学生的电脑的电量在分钟内都不为负。
思路
二分答案+贪心。每分钟都给当前续航时间最少的电脑充电,如果续航时间相同给耗电量大的电脑先充电,都相同则给剩余电量少的电脑先充电。那么可以按照此规则维护一个优先队列,每次给队首元素充电,如果其续航时间超过k则弹出队列。一共执行k次,若当前续航时间小于当前天数则失败,撑过k天或者队列为空则成功。优先队列的建堆复杂度,插入删除为,算法复杂度为。
二分右边界开太大爆long long了一次。还要注意优先队列定义规则里面的大于号和小于号。
代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5+5; ll al[maxn], be[maxn]; ll n,k; const ll inf = 2e12; struct node { ll d, a, b; // d=a/b node (ll dd, ll aa, ll bb) { d=dd; a=aa; b=bb; } bool operator < (const node &p) const { // 最后还有一个const if(d == p.d && b == p.b) return a>p.a; if(d == p.d) return b<p.b; return d > p.d; } }; priority_queue<node> q; bool check(ll mid) { priority_queue<node> qq=q; for(int i=0;i<k;i++) { if(qq.empty()) return 1; node p=qq.top(); qq.pop(); // cout << p.d << ' ' << p.a << " " << p.b << endl; // cout<<p.d <<" " << i << endl; if(p.d < i) return 0; if((p.a+mid)/p.b < k) { qq.push(node((p.a+mid)/p.b, p.a+mid, p.b)); } } return 1; } int main() { scanf("%lld%lld",&n,&k); for(int i=0;i<n;i++) scanf("%lld",&al[i]); for(int i=0;i<n;i++) scanf("%lld",&be[i]); for(int i=0;i<n;i++) { if(al[i]/be[i] < k) q.push(node(al[i]/be[i],al[i],be[i])); } ll l=0,r=inf,ans=inf,mid; while(l<=r) { // cout << "mid = " << mid << endl; mid = (l+r)>>1; if(check(mid)) ans = min(ans, mid), r=mid-1; else l=mid+1; } if(ans==inf) ans=-1; printf("%lld\n", ans); }