题意很简单,,话说我先看的这题,,,,感觉很简单才自信敲A,,,结果。。。呵了个呵。。。。
就是有几个学生,,,要么往前走一步,,,要么搬走一个箱子,,问最少时间。。。。
开始想的是大家一起往前走,,,,,一起搬,,,没事干的往前继续走,,,,,,样例真不够意思全过了。。。。然后就卡了。。。。其实随便一组数据都会错。。。。
比如 4 4 3 4 2 4之类的吧,,也记不住了当时否定了自己就去睡觉了。。。。因为有的时候一个人留在一个地方一直搬箱子,,,,比他走一步搬一步明显搬得要多得多,,,所以中心思想就来了——我们要让最少的人往后走(当然了人比箱子多那没说的了。。。。。)
恩,,,,这么想就简单多了。。。。。。但是怎么实现这个想法呢?我认为比较简单的就是枚举每一秒可能的情况,,,,,然后看看行不行,,,,,一秒一秒加,,,
但是写到这里其实还不是很会(代码能力渣渣渣!),,而且可能会超时(test 8就超时了!!!!)。。。。。。。网上比较流行的方法(什么时候才能不找题解。。哎)就是用二分。。。。这里用一下吧。。。。。。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define LL long long
int n, m;
LL stone[MAXN];
LL tmp[MAXN];
int check(LL time)
{
for(int i = 1; i <= n; i++)
tmp[i] = stone[i];
int cnt = n;
for( int i = 0; i < m; i++)
{
while(cnt >= 1 && tmp[cnt] == 0) cnt--;
if(cnt == 0) return 1;
LL tot_t = cnt;
if(tot_t > time) return 0; //剩下的点比时间还多那还扯个屁!
while(cnt >= 1 && tmp[cnt] + tot_t <= time) //可以把这一步的箱子取完。。。
{
tot_t += tmp[cnt]; //记录已经走了多长时间
tmp[cnt] = 0; //这步的为0
cnt--; //到前一步的(往前走不算步数!!)
}
if(cnt == 0) return 1; //如果到0了就是可以成功
tmp[cnt] -= (time - tot_t); //没到0就下一个人来,,这个人所对应的点拿走能动的步数的箱子。。。
}
return 0;
}
int main()
{
while(scanf("%d %d",&n, &m) != EOF)
{
LL l = 0, r = 0;
for(int i = 1; i <= n; i++)
{
scanf("%lld",&stone[i]);
r += stone[i];
}
r += n;
while(l < r)
{
LL mid = (l + r) >> 1;
if(check(mid)) //中间那个点符合
r = mid;
else //中间那个点不够
l = mid + 1;
}
printf("%lld\n",r);
}
}