• Codeforces6E_Exposition


    题意

    给定一个序列,求有多少个最长连续子序列满足最大值减最小值之差不超过(k)

    分析

    • 跟序列最大值最小值有关的可以想到单调栈,先预处理出每个数作为最大值能延伸的区间,然后枚举每个数作为最大值。
    • 最大的满足条件的连续序列显然左边就是要在([le[i],i-1])里找到大于等于(a[i]-k)的最小值对应的下标,右边同理。
    • 线段树维护区间最小值,然后再套一个二分(应该也可以不用,就一个log,不过二分容易想),求出两端能满足条件的序列端点,计算出长度更新答案。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    #define ls i<<1
    #define rs i<<1|1
    #define mid (l+r)/2
    const int N=1e5+50;
    int n,k,a[N];
    int le[N],ri[N];
    int mn[N*4];
    void build(int i,int l,int r){
        if(l==r){
            mn[i]=a[l];
            return;
        }
        build(ls,l,mid);
        build(rs,mid+1,r);
        mn[i]=min(mn[ls],mn[rs]);
    }
    int query(int i,int l,int r,int ql,int qr){
        if(ql<=l && qr>=r){
            return mn[i];
        }
        int ans=0x3f3f3f3f;
        if(ql<=mid){
            ans=min(ans,query(ls,l,mid,ql,qr));
        }
        if(qr>mid){
            ans=min(ans,query(rs,mid+1,r,ql,qr));
        }
        return ans;
    }
    set<pair<int,int> > res;
    int mx;
    int main(){
    //    freopen("in.txt","r",stdin);
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        stack<int> s;
        for(int i=1;i<=n;i++){
            while(!s.empty() && a[s.top()]<=a[i]){
                s.pop();
            }
            if(s.empty()){
                le[i]=1;
            }else{
                le[i]=s.top()+1;
            }
            s.push(i);
        }
        while(!s.empty()){
            s.pop();
        }
        for(int i=n;i>=1;i--){
            while(!s.empty() && a[s.top()]<=a[i]){
                s.pop();
            }
            if(s.empty()){
                ri[i]=n;
            }else{
                ri[i]=s.top()-1;
            }
            s.push(i);
        }
        build(1,1,n);
        for(int i=1;i<=n;i++){
            int t=a[i]-k;
            //查询[le[i],i-1] >=t 的最小值的值和位置
            int L=le[i],R=i-1;
            int lidx=i;
            while(L<=R){
                int M=(L+R)/2;
                int tm=query(1,1,n,M,i-1);
                if(tm>=t){
                    lidx=M;
                    R=M-1;
                }else{
                    L=M+1;
                }
            }
            L=i+1,R=ri[i];
            int ridx=i;
            while(L<=R){
                int M=(L+R)/2;
                int tm=query(1,1,n,i+1,M);
                if(tm>=t){
                    ridx=M;
                    L=M+1;
                }else{
                    R=M-1;
                }
            }
            int ans=ridx-lidx+1;
            if(ans>mx){
                mx=ans;
                res.clear();
                res.insert({lidx,ridx});
            }else if(ans==mx){
                res.insert({lidx,ridx});
            }
        }
        int siz=res.size();
        printf("%d %d
    ",mx,siz);
        for(auto it:res){
            printf("%d %d
    ",it.first,it.second);
        }
        return 0;
    }
    
  • 相关阅读:
    DC中为什么要用Uniquify?
    hdu 1596 find the safest road
    hdu2112 HDU Today
    hdu 2066 一个人的旅行
    poj 3026 Borg Maze
    poj 1979 Red and Black
    poj 1321 棋盘问题
    hdu 1010 Tempter of the Bone
    hdu 4861 Couple doubi
    codeforces584B Kolya and Tanya
  • 原文地址:https://www.cnblogs.com/zxcoder/p/11644804.html
Copyright © 2020-2023  润新知