UVA 1335 Beijing Guards(二分答案)

题目链接:https://vjudge.net/problem/UVA-1335

 

一道有思维的二分答案题目。

 

首先,如果$n$为偶数,那么$p=max(r_i+r_{i+1})$,不难看出,这个值便是答案的下限。

对于$n$为奇数的情况,我们就要二分答案:

首先以$r_1$为界,$left[i]$记录第$i$个人在$1$~$r_1$中取了多少个礼物,$right[i]$记录第$i$个人在$r_1+1$~$n$中取了多少个礼物。

假设有$p$种礼物,那么设第一个人的礼物是$1$~$r_1$,那么最优的策略便是:编号为偶数的人尽量往前取,编号为奇数的人尽量往后取。

其实很好理解:因为$1$本身即为奇数,$1$已经取了$1$~$r_1$,如果要使$n$($n$为奇数)的礼物最大限度不与$1$的不相同,那么就要尽可能多的取$right[]$中的礼物。

 

AC代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 const int maxn=100010;
 6 int n,left[maxn],right[maxn],r[maxn];
 7 
 8 bool check(int p){
 9     int x=r[1],y=p-r[1];
10     left[1]=x; right[1]=0;
11     for(int i=2;i<=n;i++){
12         if(i&1){
13             right[i]=min(r[i],y-right[i-1]);
14             left[i]=r[i]-right[i];
15         }
16         else{
17             left[i]=min(r[i],x-left[i-1]);
18             right[i]=r[i]-left[i];
19         }
20     }
21     return left[n]==0;
22 }
23 
24 int main(){
25     while(scanf("%d",&n)==1&&n){
26         for(int i=1;i<=n;i++) scanf("%d",&r[i]);
27         if(n==1){
28             printf("%d\n",r[1]);
29             continue;
30         }
31         r[n+1]=r[1];
32         int L=0,R=0;
33         for(int i=1;i<=n;i++) L=max(L,r[i]+r[i+1]);
34         if(n&1){
35             for(int i=1;i<=n;i++) R=max(R,r[i]*3);
36             while(L<R){
37                 int M=L+(R-L)/2;
38                 if(check(M)) R=M; else L=M+1;
39             }
40         }
41         printf("%d\n",L);
42     }
43     return 0;
44 }
AC代码

 

posted @ 2020-02-14 22:33  dfydn  阅读(158)  评论(0编辑  收藏  举报