uva 1335 - Beijing Guards

题目链接:

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;
}



你可能感兴趣的:(uva 1335 - Beijing Guards)