题目链接:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=456&page=show_problem&problem=4081
好题!不得不说贪心真的很强大和千变万化。。。
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; }