BNUZ比赛训练【补】
一道正常的cf的c题,比赛过程中想到用二分,但是贪心的思路没想好,一直没下手敲,赛后看了下题解,果然自己连贪心都不会了,简直菜啊。
题目:
http://codeforces.com/problemset/problem/551/C题目大概意思:
有n个位置,每个位置上有一种东西,需要消除他们,有m个学生,这些学生从位置0开始出发,一直只能向右走,每走一步需要花费一秒钟,每消除每个位置上的一样东西需要花费一秒钟,学生可以同时出发,问最短将这些东西消除的时间为多长。
其实很容易想到,二分答案,直接二分所需要的时间,那重点是就是怎么check了,比赛的时候由于菜,还有20分钟的时候才看过这道题,然后一开始没思路,想到二分的时候已经只有10分钟了。。然而还是那种没想到贪心的情况,所以没敲。。赛后再看回来。这个贪心真的是灰常涨姿势。
先二分所需要的时间,然后每一个学生每次优先走到最后一个所需要工作的箱子,如果可以删除完就删除完,删除完后往前移一位(这里我们把他这个人当做是先到了那个位置,工作完了,再走到后面,这样的话,步行时间永远只是走到最后面的时间),然后一直模拟即可。这里要注意一个大坑,就是他后面可能有很多个0,这样的话,就不需要去访问那些位置了,因为永远走不到,所以需要开始的时候把那些没用的去掉。在这wa了3发才反应过来。。。
下面贴上棒棒的代码
/*
@resouces: codeforces 551C
@date: 2017-3-3
@author: QuanQqqqq
@algorithm: binary search + greedy
*/
#include <bits/stdc++.h>
#define ll long long
#define maxn 100050
using namespace std;
ll a[maxn],b[maxn];
ll n,m;
bool check(ll t){
ll last = n,p = m,temp;
for(ll i = 1;i <= n;i++){
b[i] = a[i];
}
while(p-- && last){
ll hast = t - last;
for(int i = last;i >= 1;i--){
if(hast > b[i]){
hast -= b[i];
b[i] = 0;
last--;
} else {
b[i] -= hast;
break;
}
}
}
temp = n;
while(temp){
if(b[temp]){
break;
}
temp--;
}
return temp == 0;
}
ll binary_search(ll l,ll r){
ll mid;
while(l <= r){
mid = l + r >> 1;
if(check(mid)){
r = mid - 1;
} else {
l = mid + 1;
}
}
if(!check(mid))
mid++;
return mid;
}
int main(){
scanf("%lld %lld",&n,&m);
ll maxt = n;
ll judge = 0;
for(ll i = 1;i <= n;i++){
scanf("%lld",&a[i]);
judge += a[i];
}
if(!judge){
printf("0\n");
return 0;
}
while(a[n] == 0)
n--;
printf("%lld\n",binary_search(n,1e15));
}