zoukankan      html  css  js  c++  java
  • BZOJ1863 [ZJOI2006]trouble 皇帝的烦恼 [思维题,二分答案,动态规划]

    皇帝的烦恼

    题目描述见链接 .


    color{red}{正解部分}

    当是一条链时, 答案显然为 max(A[i1]+A[i])max(A[i-1]+A[i]), 但这是一个环, 需要考虑 A1A_1AnA_n 的冲突关系 .

    首先答案具有 单调性, 考虑二分答案, 二分出答案设为 midmid, 然后是 check()check() 部分 .
    再设 AnA_nA1A_1 的 最小集合交 大小为 min_inte[n]min\_inte[n], 我们的目标是使得 min_inte[n]min\_inte[n] 尽量小,
    现在与 A1A_1 不相交的集合 SS 大小为 midA1mid-A_1,
    再考虑到 An1A_{n-1}AnA_n 的影响, 可选且与A1A_1不相交 的 集合大小 为 S=mid(A1An1)|S| = mid - (A_1∪A_{n-1}) .

    SS 中的集合显然都应该加入到 AnA_n 中, 然后若还不够, 就只能使用与 A1A_1 冲突且不与 An1A_{n-1} 冲突的集合了, 这会增加 min_inte[n]min\_inte[n] 的值 .
    所以 S|S| 越大越好, 进而 A1An1=A1+An1(A1An1)A_1 ∪ A_{n-1} = A_1 + A_{n-1} - (A_1 ∩ A_{n-1}) 越小越好, 再进而 A1An1A_1 ∩ A_{n-1} 越大越好,

    为了达到这个目的, 设 max_inte[i]max\_inte[i] 表示 AiA1A_i ∩ A_1 的最大值, 则通过类似上方的分析, 可以得到以下状态转移方程,

    min_inte[i]=max(0,Ai(midAi1A1+max_intei1))min\_inte[i] = max(0, A_i - (mid - A_{i-1} - A_1 + max\_inte_{i-1}))
    max_inte[i]=min(Ai,A1,(midAi1)A1=A1min_intei1)max\_inte[i] = min(A_i, A_1, (mid-A_{i-1})∩A_1=A_1-min\_inte_{i-1}) .

    二分界限为 [0,3Amax][0, 3*A_{max}], 时间复杂度 O(NlogAmax)O(NlogA_{max}) .


    color{red}{实现部分}

    22 个要注意的点

    1. 关于 A1A_1A2A_2max_inte,min_intemax\_inte, min\_inte 要特殊处理 .
    2. 在检查 midmid 是否可行时, 需要先检查是否 mid>max(Ai+Ai1)mid > max(A_i+A_{i-1}) .
    #include<bits/stdc++.h>
    #define reg register
    
    const int maxn = 1e5 + 10;
    
    int N;
    int Ans;
    int Max_A;
    int A[maxn];
    int min_inte[maxn];
    int max_inte[maxn];
    
    bool chk(int mid){
            min_inte[1] = max_inte[1] = A[1];
            for(reg int i = 1; i < N; i ++) if(A[i] + A[i+1] > mid) return false;
            for(reg int i = 2; i <= N; i ++){
                    min_inte[i] = std::max(0, A[i] - (mid-A[i-1]-A[1]+max_inte[i-1]));
                    min_inte[i] = std::min(min_inte[i], A[i]);
                    max_inte[i] = std::min(A[1], A[1] - min_inte[i-1]);
                    max_inte[i] = std::min(max_inte[i], A[i]);
                    if(i == 2) min_inte[i] = max_inte[i] = 0;
    //                printf("%d: %d %d
    ", i, min_inte[i], max_inte[i]);
            }
            return !min_inte[N];
    }
    
    int main(){
            scanf("%d", &N);
            for(reg int i = 1; i <= N; i ++) scanf("%d", &A[i]), Max_A = std::max(Max_A, A[i]);
            if(N == 1){ printf("%d
    ", A[1]); return 0; }
            int l = 0, r = 3*Max_A;
            Ans = 0x3f3f3f3f;
            while(l <= r){
                    int mid = l+r >> 1;
                    if(chk(mid)) Ans = std::min(Ans, mid), r = mid - 1;
                    else l = mid + 1;
            }
            printf("%d
    ", Ans);
            return 0;
    }
    
  • 相关阅读:
    从头到尾彻底理解KMP
    [CF1220E] Tourism
    [CF446C] DZY Loves Fibonacci Numbers
    [CF1003E] Tree Constructing
    [CF1238E] Keyboard Purchase
    [CF915E] Physical Education Lessons
    [CF788B] Weird journey
    [CF1371E2] Asterism (Hard Version)
    [CF780E] Underground Lab
    [CF372C] Watching Fireworks is Fun
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822498.html
Copyright © 2011-2022 走看看