Educational Codeforces Round 61 (Rated for Div. 2) D. Stressful Training 详解

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

D. Stressful Training
题目大意:
比赛开始每个同学都带了电脑,但没带充电器,已知有n个同学,每个同学电脑剩余电量为a[i],每秒耗电为b[i],比赛时长为k秒。教练买了个充电器,每秒钟可以给一个电脑冲x的电;求最小的x使全体同学完成比赛。ps:第一秒不耗电,最后一秒可以小于0,电量可以为0
大佬解答:
二分答案后发现可以O(nlogn)O(nlogn)判断,想办法卡卡常即可,时间复杂度O(nlognlogs)O(nlognlogs),其中s为答案的范围。
菜鸟思维:
计算x的最小值,可以很容易想到二分;
如何通过mid验证x是否成立呢?
大佬告诉我们可以在电脑电量低于0的时刻,加一,表示此刻到此刻以前电脑至少需要充电一次。维护cnt数组,cnt[i]的前缀和即表示i以前至少要充电n次,如果n>i则表示无法满足充电需求;
那么代码为

#include 
#include 
#include 
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
LL a[210000], need[210000];
int b[210000], n, k, cnt[210000];
bool check(LL mid)
{
	 for (int i = 0; i <= k; i++)
  	cnt[i] = 0;
 	int tot = k - 1;
 	for (int i = 1; i <= n; i++)
 	{
  		if (!b[i])
  		 continue;
 	 	LL hadtime = a[i];
  		while (hadtime < need[i])
  		{	
  	 		cnt[hadtime / b[i] + 1]++;
   			hadtime += mid;
   			if (!tot)
    				return false;
   			tot--;
  		}
 }
 for (int i = 1; i <= k; i++)
 {
  	cnt[i] = cnt[i] + cnt[i - 1];
 	 if (cnt[i] > i)
   		return false;
 }
	 return true;
}
int main()
{
 	scanf("%d%d", &n, &k);
 	for (int i = 1; i <= n; i++)
  	cin >> a[i];
 	for (int i = 1; i <= n; i++)
 	{
  		scanf("%d", &b[i]);
  		need[i] = LL(k - 1)*b[i];
	 }
	 LL left, right, mid, ans = -1;
	 left = 0; right = 2e12;
 	while (left <= right)
	 {
 	 mid = (left + right) / 2;
  	if (check(mid))
  	{
   		ans = mid;
  		 right = mid - 1;
  	}
  	else
   	left = mid + 1;
	 }
 	cout << ans << '\n';
 }

你可能感兴趣的:(codeforce)