• [RMQ] Codeforces 1454F Array Partition


    题目大意

    给你一个长为 (n(3leq nleq 2 imes 10^5)) 的数组 ({a_n}),问是否能把它分成三段,第一段的最大值等于第二段的最小值等于第三段的最大值。若能,输出方案。

    题解

    预处理每一个 (a_i) 在它之前最后一次作为前缀的最大值的位置 (pre[a[i]]),以及每一个 (a_i) 在它之后最后一次作为后缀的最大值的位置 (suf[a[i]])。遍历每一个 (a[i]),若 ([pre[a[i]]+1,suf[a[i]-1]]) 的区间最小值等于 (a[i]),则数组可分为 ([1,pre[a[i]]],[pre[a[i]]+1,suf[a[i]]-1],[suf[a[i]],N]) 这三段。使用 ST 表维护即可,时间复杂度 (O(Nlog N))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define RG register int
    #define LL long long
    
    template<typename elemType>
    inline void Read(elemType &T){
        elemType X=0,w=0; char ch=0;
        while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
        while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        T=(w?-X:X);
    }
    
    template<typename elemType>
    struct ST{
        elemType dp[200005][20];
        int N;
        ST(int _N=0):N(_N){}
        void Init(elemType *data,int Len){
            N=Len;
            for(RG i=1;i<=N;i++)
                dp[i][0]=data[i];
            for(RG j=1;(1<<j)<=N;j++)
                for(RG i=1;i+(1<<j)-1<=N;i++)
                    dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
            return;
        }
        elemType Query(int L,int R){
            int K=log2(R-L+1);
            return min(dp[L][K],dp[R-(1<<K)+1][K]);
        }
    };
    ST<int> RMQ;
    map<int,int> pre,suf;
    int a[200010],pos[200010];
    int T,N;
    
    void Solve(){
        pre.clear();suf.clear();
        int mx=-1;
        for(int i=N;i>=1;--i){
            pos[i]=suf[a[i]];
            mx=max(mx,a[i]);
            suf[mx]=i;
        }
        mx=-1;
        for(int i=1;i<=N;++i){
            if(pre[a[i]] && pos[i]>i){
                int L=pre[a[i]],R=pos[i];
                if(RMQ.Query(L+1,R-1)==a[i]){
                    cout<<"YES"<<endl;
                    cout<<L<<" "<<R-L-1<<" "<<N-R+1<<endl;
                    return;
                }
            }
            mx=max(mx,a[i]);
            pre[mx]=i;
        }
        cout<<"NO"<<endl;
    }
    
    int main(){
        Read(T);
        while(T--){
            Read(N);
            for(int i=1;i<=N;++i)
                Read(a[i]);
            RMQ.Init(a,N);
            Solve();
        }
        return 0;
    }
    
  • 相关阅读:
    BZOJ3997:[TJOI2015]组合数学(DP,Dilworth定理)
    BZOJ4807:車(组合数学,高精度)
    BZOJ4008:[HNOI2015]亚瑟王(DP,概率期望)
    BZOJ1499:[NOI2005]瑰丽华尔兹(DP,单调队列)
    洛谷1514 引水入城
    洛谷 1018 乘积最大
    八数码难题
    CODEVS 1069关押罪犯
    CODEVS 1067 机器翻译
    洛谷 P1417 烹调方案
  • 原文地址:https://www.cnblogs.com/AEMShana/p/14040408.html
Copyright © 2020-2023  润新知