题意:有n个箱子形成的堆,现在有m个学生,每个学生每一秒可以有两种操作:
1: 向右移动一格
2: 移除当前位置的一个箱子
求移除所有箱子需要的最短时间。注意:所有学生可以同时行动。
思路:二分时间,判断当前限制的时间是否可以移除完所有箱子。那么如何判断呢? 设lim表示当前的时间限制,走到第
i
个堆花费
AC代码
#include <cstdio>
#include <cmath>
#include <cctype>
#include <bitset>
#include <algorithm>
#include <cstring>
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define eps 1e-10
#define inf 0x3f3f3f3f
#define PI pair<int, int>
typedef long long LL;
const double pii = acos(-1.0);
const int maxn = 1e5 + 5;
int n, m;
LL box[maxn], pbox[maxn];
bool check(LL lim) {
LL rest = 0, cnt = m;
for(int i = n-1; i >= 0; --i) {
pbox[i] = box[i];
if(rest >= pbox[i]) {
rest -= pbox[i];
pbox[i] = 0;
}
else {
pbox[i] -= rest;
rest = 0;
}
LL dis = i+1;
if(pbox[i] == 0) continue;
if(lim <= dis) return false;
//pbox[i] <= x*(lim-dis)
LL num = (LL)ceil(1.0*pbox[i]/(lim-dis));
if(num > cnt) return false;
cnt -= num;
rest += num*(lim-dis) - pbox[i];
}
return true;
}
LL solve(LL x, LL y) {
while(x < y) {
LL mid = (x+y) / 2;
if(check(mid)) y = mid;
else x = mid+1;
}
return y;
}
int main() {
while(scanf("%d%d", &n, &m) == 2) {
LL sum = 0;
for(int i = 0; i < n; ++i) {
scanf("%lld", &box[i]);
sum += box[i] + i;
}
printf("%lld\n", solve(0, sum+5));
}
return 0;
}
如有不当之处欢迎指出!