1 条题解

  • 0
    @ 2025-8-24 21:49:41

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar alksdjhfg
    None

    搬运于2025-08-24 21:49:41,当前版本为作者最后更新于2017-08-08 09:24:41,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    n<=3000000,单调队列。

    因为要同时维护最大值和最小值,所以需要两个单调队列,记录序号和最大最小值,然后

    从左往右枚举一遍O(n)的复杂度即可。

    单调队列的实现以最大值为例,当队列非空且队尾的数没有现在枚举到的这个数大时,就

    让队尾的数出队,因为在接下来的情况中它们永远不会是一个区间的最大值。最小值的队列同理。把当前位置加入最大最小值队列。然后比较最大值队列的队首即最大值和最小值,如果它们的差超过了k,就看一下最大值和最小值的队首哪个的序号更小,让序号更小的出队,同时更新当前队列的最前节点的位置,继续比较两个的队首,直到最大最小值的差小于等于k时,用当前位置减去当前队列的最前节点的位置再加一,就是目前的符合条件的序列长度,与最长值比较即可。

    当前队列的最前节点的位置初始值为1.

    代码如下:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define ll long long
    ll k,n,a[3000005],q_mx[3000005],q_mn[3000005];
    ll head_mx,head_mn,tail_mx,tail_mn,len,pre;
    int main(){
    //    freopen("1.in","r",stdin);
        scanf("%lld%lld",&k,&n);
        len=0;
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        q_mx[1]=1;q_mn[1]=1;pre=1;
        head_mx=1;tail_mx=1;head_mn=1;tail_mn=1;
        for(int i=2;i<=n;i++){
            while(head_mx<=tail_mx&&a[q_mx[tail_mx]]<a[i])tail_mx--;
            while(head_mn<=tail_mn&&a[q_mn[tail_mn]]>a[i])tail_mn--;
            q_mx[++tail_mx]=i;q_mn[++tail_mn]=i;
            while(a[q_mx[head_mx]]-a[q_mn[head_mn]]>k){
                if(q_mx[head_mx]<q_mn[head_mn]){pre=q_mx[head_mx]+1;head_mx++;}
                else {pre=q_mn[head_mn]+1;head_mn++;}
            }
            //pre=min(q_mx[head_mx],q_mn[head_mn]);
            len=max(len,i-pre+1);
        }
        printf("%lld",len);
    }
    
    • 1

    信息

    ID
    2588
    时间
    1000ms
    内存
    125MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者