cf#307-C - GukiZ hates Boxes-二分+贪心

时间:2022-12-19 17:22:57

http://codeforces.com/contest/551/problem/C

题意:

一排n个点,每个点有a[i]个box,

m个人,每个人可以花1s作两个操作之一:

  1:i移动到i+1

  2:移掉当前位置一个box

要求把所有box移除完需要的最小时间


思路:二分+贪心,先二分时间,在判断X时

假如我们能用x秒解决,怎样是最优的方案呢?

我们尽可能让每个人都不闲着,首先每个人有X秒时间。

我们遍历1到第n堆box,

模拟人移除box, 如果第i个人的时间大于 移除box+走路的时间,则 移除掉,然后继续往后走【mark下他的当前位置,待会计算走路花的时间】

如果时间不够移除,则把这个人时间全部用完,然后再让下一个人继续做


如此进行,当  人数变为0 时还没结束,则return 0;如果最后移除完所有box ,则return 1;

  

【注意一个trick,给出的堆可能是这样的  1 2 3 0 0 0 ,也就是当我们移除前三堆后就结束了,不需要再花费时间往后走,所以要记录一下剩下box总数】


 

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const __int64 inf=2147483647;
const double pi=acos(-1.0);
double eps=0.000001;
__int64 min(__int64 a,__int64 b)
{return a<b?a:b;}
__int64 max(__int64 a,__int64 b)
{
	return a<b?b:a;
}

__int64 tm[100005];
__int64 tmp[100005];

__int64 m,n,tol=0;
__int64 bin(__int64 x)
{
	__int64 ha	s=x;
	__int64 ren=m;
	__int64 last=0;
	__int64 i;
	for (i=1;i<=n;i++) tmp[i]=tm[i];
	__int64 tmp_tol=tol;
	for (i=1;i<=n;i++)
	{	
		if (!tmp_tol) return 1;	//所有箱子移除了,则不需要往后走了
		if (has>=tmp[i]+i-last)
		{
			has-=tmp[i]+i-last;
			last=i;			//记录上次停留的位置
			tmp_tol-=tmp[i];		//总box数减少
		}
		else
		{
			has-=i-last;	//减去走路时间
			tmp[i]-=has;		//移除部分箱子
			tmp_tol-=has;	//总box数减少
			ren--;			//一个人时间耗尽
			if (ren==0) return 0;		//当前时间不足完成任务
			has=x;last=0;			//新的一个人
			i--;
		} 
	}
	return 1;
	
}
int main()
{    
	__int64 i;
	scanf("%I64d%I64d",&n,&m);
	for (i=1;i<=n;i++)
		scanf("%I64d",&tm[i]),tol+=tm[i]; 
	__int64 l=0,r=1e18;
	__int64 ans;
	
	while(l<=r)
	{
		__int64 mid=(l+r)>>1;
		if (bin(mid))
			r=mid-1,ans=mid;
		else
			l=mid+1; 
	}
	printf("%I64d\n",ans);
	
	return 0;
	
}