题目链接:
题目大意:
给出n个连续的堆,m个学生,初始状态下所有的学生都在位置0,每一秒每个学生可以选择向前走一步,或者搬掉当前堆的一块砖,问搬完所有砖的最短时间。
题目分析:
首先想到在最短时间t的情况下能搬完的话,那么对于一个大于t的时间一定也能够搬完所有的砖,那么利用这条性质,我们就可以利用二分法解决这个问题,在判断当前条件下是否合法时,我们可以采取贪心策略,也就是对于当前最远的非0堆,一定会有人取搬完它,那么我们直接找到足够的人取搬完它,可能会有人有时间剩余,那么这个人可以在中途停下来搬任何一堆,所以不影响当前情况下的决策,那么我们就从后向前扫一遍,如果能搬完所有的砖,那么当前情况合法,如果不能,那么当前情况不合法。
很水的题,主要是看想到二分之后,能不能逆向的想到这个贪心策略
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define MAX 100007
using namespace std;
typedef long long LL;
LL n,m;
LL h[MAX];
bool check ( LL x )
{
LL num = m;
LL id = n+1;
LL temp = 0;
while ( num-- )
{
LL tx = x;
while ( temp == 0 )
{
if ( id == 1 ) return true;
temp = h[--id];
}
if ( tx <= id ) return false;
tx -= id;
while ( tx >= temp )
{
tx -= temp;
temp = 0;
while ( temp == 0 )
{
if ( id == 1 ) return true;
temp = h[--id];
}
}
temp -= tx;
if ( temp == 0 && id == 1 ) return true;
}
//if ( temp == 0 && id == 1 )
return false;
}
int main ( )
{
while ( ~scanf ( "%I64d%I64d" , &n , &m ) )
{
LL r = 0 , l = 1 , mid;
for ( int i = 1 ; i <= n ; i++ )
{
scanf ( "%I64d" , &h[i] );
r += h[i]+i;
}
while ( l != r )
{
mid = l + r>> 1;
if ( check ( mid ) ) r = mid;
else l = mid+1;
}
printf ( "%I64d\n" , l );
}
}