Educational Codeforces Round 61 (Rated for Div. 2) D. Stressful Training //二分

14 篇文章 0 订阅
10 篇文章 0 订阅

https://codeforces.com/contest/1132/problem/D

 题题意是有n台笔记本,要同时使用k个时间,每个时间可以给一台电脑充电x电量,求最小的x使得n台笔记本可以度过k时间。

显然 x越大越好,如果有答案,一定在某个值刚好成立,线性问题,直接二分x。

首先想法是维护一个还能使用时间最小的电脑(a[i]/b[i])最小,然后模拟,贪心的给能存活时间最短的电脑优先充电。

坑的地方是,multiset不能过(直接卡到22组,预先sort卡到27组),

优先队列或线段树(维护最小值)可以过。 (???)

https://blog.csdn.net/ccsu_cat/article/details/88310531(线段树也几乎是卡死)

贴优先队列代码(小心数据范围可能有爆的地方)

复杂度(O(K*log(ans)*log(n))

#include<bits/stdc++.h>
using namespace std;
#define LL long long
struct no{
	LL a;
	LL b;
	LL c;
}lap[200005];
bool operator<(const no &x,const no &y){
	return x.c>y.c;
}
int n,k;
bool check(LL mid){
	priority_queue<no> q;
	for(int i=1;i<=n;i++) q.push(lap[i]);
	for(LL i=1;i<k;i++){
		no cur=q.top();q.pop();
		cur.a=cur.a+mid;
		cur.c=cur.a/cur.b;
		q.push(cur);
		if(q.top().c<i) return 0;
	}
	return 1;
}
LL binary(){
	LL l=0,r=1e13;
	LL ans=LLONG_MAX;
	while(l<=r){
		LL mid=(l+r)/2;
		if(check(mid)){
			ans=mid;
			r=mid-1;
		} 
		else  l=mid+1;
	}
	return ans;
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>lap[i].a;
	for(int i=1;i<=n;i++) {
		cin>>lap[i].b; 
		lap[i].c=lap[i].a/lap[i].b;
	}
	LL ans=binary();
	if(ans==LLONG_MAX) cout<<-1;
	else cout<< ans; 
	return 0;
} 

题解有一种复杂度(O(K*log(ans))的做法

用vector维护小于生命期小于k的电脑的编号。 v[i] 里面放 当前生命期为i天的 电脑编号,然后模拟一遍写check。

 By RSHS, contest: Educational Codeforces Round 61 (Rated for Div. 2), problem: (D) Stressful Training, Accepted, #

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn=2*1e5+5; 
int n,k;
LL a[maxn],b[maxn];
vector<int> v[maxn];
bool check(LL mid){
	for(int i=0;i<=k;i++) v[i].clear();
	LL cnt[maxn];
	for(int i=1;i<=n;i++){
		LL x=a[i]/b[i];
		if(x>=k) continue;
		cnt[i]=a[i]%b[i];
		v[x].push_back(i);
	}
	int p=0;
	for(LL i=0;i<k;i++){
		while(v[p].size()==0&&p<k)
			p++;
		if(p==k) break;
		int u=v[p].back();
		v[p].pop_back();
		LL newa=p*b[u]+cnt[u]+mid;
		LL uu=newa/b[u];
		if(uu<k){
			v[uu].push_back(u);
			cnt[u]=newa%b[u];
		}
		if(v[i].size()!=0) return false;
		
	}
	return true;
}
LL binary(){
	LL l=0,r=1e15;
	LL ans=LLONG_MAX;
	while(l<=r){
		LL mid=(l+r)/2;
		if(check(mid)){
			ans=mid;
			r=mid-1;
		} 
		else  l=mid+1;
	}
	return ans;
}
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>k;k--;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	LL ans=binary();
	if(ans==LLONG_MAX) cout<<-1;
	else cout<< ans; 
	return 0;
} 

优先队列(几乎卡死)

 vector模拟优化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值