zoukankan      html  css  js  c++  java
  • AGC028E

    题意

    给出一个长度为 (n) 的排列 (P)
    一个长度为 (n) 的 01 串 (S) 被成为好的,当且仅当:

    • 按照以下方式构造序列 (X,Y)
      • 首先我们让 (X,Y) 为空的序列
      • 对于每一个 (i=1,2,ldots,N),按照顺序,如果 (S_i=0),在 (X) 后面添加 (P_i);如果 (S_i=1),在 (Y) 后面添加 (P_i)
    • (X,Y) 的前缀最大值的个数相同

    判断是否存在一个好的字符串,并且输出字典序最小的那一个。(n leq 2 imes 10^5)

    题解

    最小化字典序,我们就会考虑如何去判断某个确定的前缀是否合法。

    我们将 (X,Y) 内的前缀最大值分成两类:原值和新值。原值的意思就是 (P) 中的前缀最大值,新值就指的不是 (P) 中的前缀最大值。

    我们考虑确定好这个前缀后,设 (X,Y) 的前缀最大值数量为 (x,y),一个结论是:如果这个前缀合法,那么一定有至少一个序列,满足还没填的那一块只有原值。

    证明:假设都有新值的话,考虑是 (a,b)(a)(X) 内是新值的原因是,把它挡住的原值被放到了 (Y) 里;(b) 同理。所以交换 (a,b) 后这两个新值都消失了,并且还是保证前缀最大值相同的。所以肯定能把一个序列的新值个数削成 (0)

    于是我们就可以找一下等量关系:设 (k) 表示还没填的 (P) 中原值的数量。我们设是 (A) 的后面只有原值,那么设 (B)(a) 个原值,(b) 个新值,(A) 就有 (k-a) 个原值,可以列出等式:

    [egin{align*} a+b+y &= k-a+x\ 2a+b &= k+x-y end{align*} ]

    我们考虑找一下 (2a+b) 的意义:就是原值的贡献是 (2),新值的贡献是 (1)。所以问题就在于,能否从 (B) 后面选出一个上升的序列,满足拼起来之后还是一个前缀最大值,并且分数是 (2a+b)

    但是这样如果直接 dp 的话是二维的状态不好 dp。但是我们观察到:如果能选出一个 (x geq 2),一定能选出一个值为 (x-2) 的 dp。所以我们只关心当前情况下能选出的最大奇数/偶数分数。那么就可以设 (f_{i,0/1}) 表示考虑后缀 (i) ,强制选择 (a_i),偶数/奇数的最大得分,转移就是:

    [f_{i,x} = max_{j > i,a_j > a_i} f_{j,x'} ]

    从后向前 dp,只需要考虑第二个限制,线段树优化复杂度 (O(n log n))

    不过注意一下我们这里查询的是 (i geq x,a_i geq a_x) 的最大值,所以最后还是要倒着来一遍线段树的。

    (Y) 是只有原值的情况类似推式子集合。等式是 (2a+b = k+y-x)

    启发:

    1. 在做物品权值的时候,如果有性质如果 (x) 可以,那么 (x-a) 也可以,就可以考虑求出 (mod a = i) 的最大/最小值来优化。有的时候需要跑最短路(其实这个就是同余最短路,也告诉我们某些背包问题也可以用这个东西优化)
    2. 这个题一开始 (A,B) 原值新值都有,我们注意到原值不管在哪里都是前缀最大值,所以我们要考虑能否调整让问题变得简单。

    代码

    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define DB double
    #define U unsigned
    #define P std::pair
    #define LL long long
    #define LD long double
    #define pb emplace_back
    #define MP std::make_pair
    #define SZ(x) ((int)x.size())
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 2e5 + 5;
    
    struct DS{
        int mx[MAXN<<2];
        DS(){CLR(mx,~0x3f);}
        #define lc ((x)<<1)
        #define rc ((x)<<1|1)
    
        inline void update(int x,int l,int r,int p,int d){
            if(l == r) return (void)(mx[x] = d);
            int mid = (l + r) >> 1;
            if(p <= mid) update(lc,l,mid,p,d);
            else update(rc,mid+1,r,p,d);
            mx[x] = std::max(mx[lc],mx[rc]);
        }
    
        inline int query(int x,int l,int r,int L,int R){
            if(L == 0) L = 1;
            if(l == L && r == R) return mx[x];
            int mid = (l + r) >> 1;
            if(R <= mid) return query(lc,l,mid,L,R);
            if(L > mid) return query(rc,mid+1,r,L,R);
            return std::max(query(lc,l,mid,L,mid),query(rc,mid+1,r,mid+1,R));
        }
    }tr[2];
    
    int n,a[MAXN];
    bool mx[MAXN];
    int res[MAXN];
    
    int main(){
        scanf("%d",&n);
        FOR(i,1,n) scanf("%d",a+i);
        int t = 0;
        FOR(i,1,n){
            t = std::max(t,a[i]);
            mx[i] = t == a[i];
        }
        tr[0].update(1,1,n+1,n+1,0);
        ROF(i,n,1){
            int f[2];CLR(f,~0x3f);
            FOR(j,0,1) f[j] = tr[j^mx[i]^1].query(1,1,n+1,a[i],n+1)+1+mx[i];
            FOR(j,0,1) tr[j].update(1,1,n+1,a[i],f[j]);
        }
        int x = 0,y = 0,k = 0,lx = 0,ly = 0;
        FOR(i,1,n) k += mx[i];
        FOR(i,1,n){
            k -= mx[i];
            FOR(j,0,1) tr[j].update(1,1,n+1,a[i],~0x3f3f3f3f);
            // 0
            x += lx < a[i];
            if((x+k-y >= 0 && tr[(x+k-y)%2].query(1,1,n+1,ly,n+1) >= x+k-y) || (k+y-x >= 0 && tr[(k+y-x)%2].query(1,1,n+1,std::max(lx,a[i]),n+1) >= k+y-x)){
                res[i] = 0;lx = std::max(lx,a[i]);
                continue;
            }
            x -= lx < a[i];y += ly < a[i];
            res[i] = 1;ly = std::max(ly,a[i]);
        }
        if(x != y) return puts("-1"),0;
        FOR(i,1,n) putchar('0'+res[i]);
        puts("");
        return 0;
    }
    
    
  • 相关阅读:
    [模板] 循环数组的最大子段和
    [最短路][几何][牛客] [国庆集训派对1]-L-New Game
    [洛谷] P1866 编号
    1115 Counting Nodes in a BST (30 分)
    1106 Lowest Price in Supply Chain (25 分)
    1094 The Largest Generation (25 分)
    1090 Highest Price in Supply Chain (25 分)
    树的遍历
    1086 Tree Traversals Again (25 分)
    1079 Total Sales of Supply Chain (25 分 树
  • 原文地址:https://www.cnblogs.com/rainair/p/14456523.html
Copyright © 2011-2022 走看看