• 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;
    }
    
  • 相关阅读:
    XamarinSQLite教程在Xamarin.iOS项目中定位数据库文件
    在Xamarin.iOS项目中使用预设数据库
    函数封装多个不同按钮的点击事件
    ajax请求数据动态渲染表格
    计算历时长度
    layui单文件上传
    滚动到顶部固定
    下载
    第一个项目技术总结
    单选框
  • 原文地址:https://www.cnblogs.com/zxcoder/p/11644804.html
Copyright © 2020-2023  润新知