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
  • 相关阅读:
    原生态ajax
    用js提交表单,没有submit按钮如何验证,使用button提交方法
    易买网吐血文档(图片拖不上来,要文档留下联系)
    时序图Sequence DiaGram
    starUML用例图
    泛型自动扩容的原理
    深入C#数据类型
    了解.NET框架
    自定义jstl标签实现页面级的权限控制
    SharePoint 2013 REST 服务使用简介
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9804048.html
Copyright © 2011-2022 走看看