题目链接:
好题!不得不说贪心真的很强大和千变万化。。。
1. 二分答案p,编号为偶数的尽量往前取,编号为奇数个的尽量往后取。
2. 第一个取第1~r1个。那么之后的怎么取的和记录呢? 刘汝佳告诉了我们一个很好的方法,只需要记录之后每个人在【1~r1】和【r1+1~n】中取了几个。然后,看最后一个是否有取到【1~r1】范围的即判断是否冲突。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
const int maxn = 100010;
int n, r[maxn], left[maxn], right[maxn];
inline bool check(int p){
int r1=r[0];
left[0] = r1;
right[0] = 0;
for(int i=1; i<n; ++i){
if(i&1){// 第偶数个,尽量往前取
left[i] = min(r1-left[i-1], r[i]);
right[i] = r[i]-left[i];
}else{ //第奇数偶个,尽量往后取
right[i] = min(p-r1-right[i-1], r[i]);
left[i] = r[i] - right[i];
}
if(left[i] + right[i] < r[i]) return false;
}
return left[n-1] == 0;
}
// 读入加速
inline int read_int(){
char c = getchar();
while(!isdigit(c)) c = getchar();
int x = 0;
while(isdigit(c)){
x = x*10+c-'0';
c=getchar();
}
return x;
}
int main(){
while(~scanf("%d", &n) && n){
for(int i=0; i<n; ++i)
r[i] = read_int();
if(n==1){
printf("%d\n", r[0]);
continue;
}
r[n] = r[0];
int L=0, R=0;
for(int i=0; i<n; ++i)
L = max(L, r[i]+r[i+1]);
if(n & 1){
for(int i=0; i<n; ++i)
R = max(R, r[i]*3);
while(L < R){
int m = (L+R) >> 1;
if(check(m)) R = m;
else L = m + 1;
}
}
printf("%d\n", L);
}
return 0;
}