zoukankan      html  css  js  c++  java
  • Luogu 4409 [ZJOI2006]皇帝的烦恼

    BZOJ 1863

    lyd口中的夹B递推。

    挺妙的解法。

    第一个感觉是找到一个最大的相邻的$a_i + a_{i - 1}$就可以了,但是这个想法大概只对了一半,一半的意思是说只有在$n$为偶数的时候才适用,因为只有在偶数的时候,所有数能恰好地被分成两组,两组互不干扰。

    奇数的时候就相当于多出了一个$1$,怎么办呢?

    显然可以二分答案吧,设$mid$表示当前二分到的颜色的数量。

    设$f_i$表示在满足$i - 1$和$i$的限制的条件下,$i$和$1$的颜色冲突的最大个数,再设$g_i$表示这个最小个数,那么有初态$f_1 = g_1 = a_i$。

    然后对于$forall i in [2, n]$,有

        $f_i = min(a_i, a_1 - g_{i - 1})$

        $g_i = max(0, a_i - (mid - a_{i - 1} - a_1 + f_{i - 1}))$

    解释一下这个式子,$i$最大应该是$i - 1$最小,但是这样的选择又要受到$a_i$的条件的限制,所以取个$min$。

    想让$i$最小,但是一定要满足$i - 1$的限制,所以可选的颜色数是$mid - a_{i - 1}$再减掉之前$i - 1$和$1$的最大冲突数$a_1 - f_{i - 1}$,然后还要和$0$取个$max$。

    时间复杂度$O(nlogMaxn)$。

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    const int N = 20005;
    const int inf = 1 << 30;
    
    int n, a[N], f[N], g[N];
    
    inline void read(int &X) {
        X = 0; char ch = 0; int op = 1;
        for(; ch > '9'|| ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    inline int max(int x, int y) {
        return x > y ? x : y;
    }
    
    inline void chkMax(int &x, int y) {
        if(y > x) x = y;
    }
    
    inline int min(int x, int y) {
        return x > y ? y : x;
    }
    
    inline bool chk(int mid) {
        f[1] = g[1]= a[1];
        for(int i = 2; i <= n; i++) {
            f[i] = min(a[i], a[1] - g[i - 1]);
            g[i] = max(0, a[i] - (mid - a[i - 1] - a[1] + f[i - 1]));
        }
        return !g[n];
    }
    
    int main() {
        read(n);
        int ln = 0, rn = inf, mid, res = inf;
        for(int i = 1; i <= n; i++) {
            read(a[i]);
            if(i > 1) chkMax(ln, a[i] + a[i - 1]);
        }
        chkMax(ln, a[1] + a[n]);
    
        if(n % 2 == 0) return printf("%d
    ", ln), 0;
    
        for(; ln <= rn; ) {
            mid = (ln + rn) / 2;
            if(chk(mid)) res = mid, rn = mid - 1;
            else ln = mid + 1;
        }
    
        printf("%d
    ", res);
        return 0;
    }
    View Code
  • 相关阅读:
    JeePlus:代码生成器
    JeePlus:API工具
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9804048.html
Copyright © 2011-2022 走看看