题解
拿到题,没什么头绪,我们模拟一下,很容易得出一个结论:
如果$n$为偶数,那么答案就是$max(r[i]+r[i+1])$。具体方案就是,如果$i$为奇数,那么取$[1,r[i]]$;若$i$为偶数,则取$[ans-r[i]+1,ans]$。
同样我们此时的$ans$是答案的下界。
可当$n$为奇数时,我们这样贪心策略出现问题就是由于$1$和$n$都是奇数,会取$[1,r[1]]$,$[1,r[n]]$显然会重复,那么奇数我们就不能这样做了。
我们由$n$为偶数的思想,我们还是让$1$号取$[1,r[1]]$,那么就要让$n$尽量往“后”取,这样$n-1$就要尽量往“前”取……
因此我们得出“除$1$以外奇数往后取,偶数往前取”,那么我们只需要通过假定的$ans$值,做一遍模拟即可。
对于如何选取$ans$,我们可以去二分。
另外一个方面,我们发现我们不需要知道我们到底是取了哪些值,我们最后只要知道是不是第$n$个人取了$[1,r[1]]$的数。那么我们把所有的数分为$[1,r[1]]$和$[r[1],ans]$两个区间,我们在区间内讨论即可。
另外:注意$n == 1$的时候的特判,因为这个$wa$了很多次。
1 //It is made by Awson on 2017.9.18 2 #include <map> 3 #include <set> 4 #include <cmath> 5 #include <ctime> 6 #include <queue> 7 #include <stack> 8 #include <cstdio> 9 #include <string> 10 #include <vector> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 #define LL long long 16 #define Max(a, b) ((a) > (b) ? (a) : (b)) 17 #define Min(a, b) ((a) < (b) ? (a) : (b)) 18 #define Abs(a) ((a) < 0 ? (-(a)) : (a)) 19 using namespace std; 20 const int N = 100000; 21 22 int n, r[N+5]; 23 24 bool judge(int p) { 25 int Left[N+5] = {0}, Right[N+5] = {0}; 26 int x = r[1], y = p-r[1]; 27 Left[1] = x; 28 for (int i = 2; i <= n; i++) { 29 if (i%2) { 30 Right[i] = Min(y-Right[i-1], r[i]); 31 Left[i] = r[i]-Right[i]; 32 } 33 else { 34 Left[i] = Min(x-Left[i-1], r[i]); 35 Right[i] = r[i]-Left[i]; 36 } 37 } 38 return Left[n] == 0; 39 } 40 void work() { 41 int L = 0, R = 0; 42 for (int i = 1; i <= n; i++) 43 scanf("%d", &r[i]); 44 if (n == 1) { 45 printf("%d\n", r[1]); 46 return; 47 } 48 r[n+1] = r[1]; 49 r[n+2] = r[2]; 50 for (int i = 1; i <= n; i++) { 51 L = Max(L, r[i]+r[i+1]); 52 R = Max(R, r[i]+r[i+1]+r[i+2]); 53 } 54 if (!(n%2)) 55 printf("%d\n", L); 56 else { 57 int ans = R; 58 while (L <= R) { 59 int mid = (L+R) >> 1; 60 if (judge(mid)) R = mid-1, ans = mid; 61 else L = mid+1; 62 } 63 printf("%d\n", ans); 64 } 65 } 66 67 int main() { 68 while ((~scanf("%d", &n)) && n) 69 work(); 70 return 0; 71 }
时间: 2024-10-19 09:39:38