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; }