ZJOI2006 皇帝的烦恼 二分+DP

版权声明:本文为DyingShu原创文章,转载请注明出处哦。 https://blog.csdn.net/DyingShu/article/details/82054242

传送门

初看题目,感觉就是道水题,判一下奇偶性就行
考完了才知道,浙江的题嘿嘿
结果最后模拟赛只拿了20。。。

题解:
二分答案,check的时候DP,设 M a x [ i ] 为第i个人最多和第1个人勋章相同的个数, M i n [ i ] 为第i个人最少和第1个人勋章相同的个数
于是就有

  • M a x [ i ] = m i n ( a [ i ] , a [ 1 ] M i n [ i 1 ] )
  • M i n [ i ] = m a x ( 0 l l , a [ i ] ( t ( a [ 1 ] + a [ i 1 ] M a x [ i 1 ] ) ) )

判一下 M i n [ n ] 是否为0,就结束了…
洛谷的题解貌似有 O ( n ) 的做法,不过我没看懂

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 30001;

int a[MAXN], n;
int Max[MAXN], Min[MAXN];

inline int read(){
    int k = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){k = k*10 + ch - '0'; ch = getchar();}
    return k * f;
}

bool check(int t){
    memset(Max, 0, sizeof(Max));
    memset(Min, 0x3f, sizeof(Min));
    Max[1] = Min[1] = a[1];
    for(int i = 2; i <= n; i++){
        Max[i] = min(a[i], a[1] - Min[i - 1]);
        Min[i] = max(0, a[i] - (t - (a[1] + a[i - 1] - Max[i - 1])));
    }
    return Min[n] == 0;
}

int main(){
    n = read();
    int l = 0, r = 0, mid;
    for(int i = 1; i <= n; i++){
        a[i] = read();
        r += a[i];
    }
    a[n + 1] = a[1];
    while(l <= r){
        mid = (l + r) >> 1;
        if(check(mid)) r = mid - 1;
        else l = mid + 1;
    }
    for(int i = 1; i <= n; i++){
        l = max(l, a[i] + a[i + 1]);
    }

    printf("%d", l);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/DyingShu/article/details/82054242
今日推荐