*CF1132D.Stressful Training(二分+队列+贪心)

题目链接:https://vjudge.net/problem/CodeForces-1132D
题意:给n个笔记本,每个笔记本有初始电量ai和每个时间点耗电量bi,要求在整个会议k个时间内,给出最小单位时间充电量x来保证每台笔记本在每个时间点都是有电的(电量>=0),每个时间点只可以给一台笔记本充x电量。
解题思路:先求出每个笔记本在什么时候电量耗尽需要充电,即ai/bi+1,然后按需要充电的时间点从小到大排序,即最需要充电的放在前面,这里直接利用优先队列就可以,遍历每个时间点1到k,如果当前笔记本需要充电的最晚时间比i小的话,那么就说明无法满足。但当前的笔记本最晚充电时间已经超过了k或者遍历了每个时间点没有出现不满足条件的情况,那么说明所有的笔记本都能够满足条件。
PS:注意没有一台笔记本需要充电的情况
然后利用二分利用上面的思路去寻找需要的最合适的答案即可,ans初始化为-1(方便找不到答案时候-1的直接输出),L=0,R=max(bi)*k或者取一个特别大的数比如1e13也可以。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define maxn 210000
#define ll long long
struct node{
	ll a;
	ll b;
	ll cnt;
}lt[maxn];
ll maxr;
int n,k;
int len;
struct cmp{
	bool operator ()(const node a,const node b) const{
		return a.cnt>b.cnt;
	}
};
int check(ll x){
	priority_queue<node,vector<node>,cmp> q;
	for(int i=1;i<=n;i++){
		if(lt[i].cnt<=k)
			q.push(lt[i]);
	}
	if(q.empty())
		return 1;
	for(int i=1;i<=k;i++){
		node tmp=q.top();
	    q.pop();
		if(tmp.cnt>k)
			return 1;
		if(tmp.cnt<i){
			return 0;
		}
		tmp.a+=x;
		tmp.cnt=tmp.a/tmp.b+1;
		q.push(tmp);
	}
	return 1;
}
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
		scanf("%lld",&lt[i].a);
	for(int i=1;i<=n;i++){
		scanf("%lld",&lt[i].b);
		lt[i].cnt=lt[i].a/lt[i].b+1;
	    maxr=max(maxr,lt[i].b*k);
	}
	ll L=0;
	ll R=maxr;
	ll ans=-1;
	while(L<=R){
		ll mid=(L+R)/2;
		if(check(mid)){
			R=mid-1;
			ans=mid;
		}
		else
			L=mid+1;
	}
	printf("%lld\n",ans);
	return 0;
}


猜你喜欢

转载自blog.csdn.net/littlegoldgold/article/details/106653545