zoukankan      html  css  js  c++  java
  • 【单调队列+尺取】HDU 3530 Subsequence

    acm.hdu.edu.cn/showproblem.php?pid=3530

    【题意】

    • 给定一个长度为n的序列,问这个序列满足最大值和最小值的差在[m,k]的范围内的最长子区间是多长?

    【思路】

    • 对于序列中特定的位置j,我们固定右端j考察左端i,发现[i,j]内的最大值随i的增大而非严格递减
    • 对于序列中特定的位置j,我们固定右端j考察左端i,发现[i,j]内的最小值随i的增大而非严格递增
    • 所以[i,j]内最大值与最小值的差随i的增大而递减
    • 对于序列中特定的位置i,我们固定左端i考察右端j,发现[i,j]内的最大值随j的增大而非严格递增
    • 对于序列中特定的位置i,我们固定左端i考察右端j,发现[i,j]内的最小值随j的增大而非严格递减
    • 所以[i,j]内最大值与最小值的差随i的增大而递增
    • 所以我们可以尺取,即如位置j对应的左端为l,那么i+1的从l以后找
    • 两个单调队列mx和mn分别维护最大值和最小值
    • mx中存放的是a中数的下标(单调递增),对应的a中的数是单调递减
    • mn中存放的是a中数的下标(单调递增),对应的a中的数是单调递增
    • 当a[mx[lx]]-a[mn[ln]]>k时,出队列的是mx[lx]和mn[ln]较小的一个,这样才能保证最长子区间
    • 当a[mx[lx]]-a[mn[ln]]<m时,不需做任何操作,因为差是随左端点的增大而递减的,如果a[mx[lx]]-a[mn[ln]]<m,只能不更新ans

    【AC】

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 int n,m,k;
     5 const int maxn=1e5+2;
     6 int a[maxn];
     7 int mx[maxn],lx,rx;
     8 int mn[maxn],ln,rn;
     9 int l,ans;
    10 int main()
    11 {
    12     while(~scanf("%d%d%d",&n,&m,&k))
    13     {
    14         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    15         lx=ln=1;rx=rn=0;l=0;
    16         ans=0;
    17         for(int i=1;i<=n;i++)
    18         {
    19             while(lx<=rx&&a[mx[rx]]<=a[i]) rx--;
    20             mx[++rx]=i;
    21             while(ln<=rn&&a[mn[rn]]>=a[i]) rn--;
    22             mn[++rn]=i;
    23             while(lx<=rx&&ln<=rn&&a[mx[lx]]-a[mn[ln]]>k)
    24             {
    25                 if(mx[lx]>=mn[ln])
    26                 {
    27                     l=mn[ln];
    28                     ln++;
    29                 }
    30                 else
    31                 {
    32                     l=mx[lx];
    33                     lx++;
    34                 }
    35             }
    36             if(a[mx[lx]]-a[mn[ln]]>=m)
    37                 ans=max(ans,i-l);
    38         }
    39         printf("%d
    ",ans);
    40     }
    41     return 0;
    42 }
    单调队列+尺取

     【疑问】

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 int n,m,k;
     5 const int maxn=1e5+3;
     6 int a[maxn];
     7 int mx[maxn];
     8 int mn[maxn];
     9 struct node
    10 {
    11     int x;
    12     int pos;
    13 }q[maxn];
    14 bool judge(int mid)
    15 {
    16     memset(q,0,sizeof(q));
    17     memset(mx,0,sizeof(mx));
    18     memset(mn,0,sizeof(mn));
    19     int head=1,tail=0;
    20     for(int i=1;i<=n;i++)
    21     {
    22         while(tail>=head&&q[tail].x<a[i]) tail--;
    23         q[++tail].x=a[i];q[tail].pos=i;
    24         while(q[head].pos<=i-mid) head++;
    25         if(i>=mid) mx[i]=q[head].x;
    26     }
    27     
    28     head=1,tail=0;
    29     for(int i=1;i<=n;i++)
    30     {
    31         while(tail>=head&&q[tail].x>a[i]) tail--;
    32         q[++tail].x=a[i];q[tail].pos=i;
    33         while(q[head].pos<=i-mid) head++;
    34         if(i>=mid) mn[i]=q[head].x;
    35     }
    36     for(int i=mid;i<=n;i++)
    37     {
    38         if(mx[i]-mn[i]>=m&&mx[i]-mn[i]<=k)
    39         {
    40             return true;
    41         }
    42     }
    43     return false;
    44 }
    45 int main()
    46 {
    47     while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    48     {
    49         for(int i=1;i<=n;i++)
    50         {
    51             scanf("%d",&a[i]);
    52         }
    53         int l=1,r=n;
    54         while(l<=r)
    55         {
    56             int mid=(l+r)>>1;
    57             if(judge(mid))
    58             {
    59                 l=mid+1;
    60             }
    61             else
    62             {
    63                 r=mid-1;
    64             }
    65         }
    66         printf("%d
    ",l-1);
    67     }
    68     return 0;
    69 }
    WA

    不知道这个二分答案,然后用单调队列判断可行性为啥是挂的orz,我感觉没错.....希望哪位仁兄看到了帮忙指点一下,小弟不尽感激~

  • 相关阅读:
    代理的原理
    nodemon:让node自动重启
    http与https的区别
    Content-Type:几种常用数据编码格式
    vue ssr服务端渲染
    vue 实现文件上传和文件下载
    vue element-ui表格里时间戳转换成时间显示
    vue npm start 自动打开网页
    yearProgress.vue
    vuejs中class与style的绑定
  • 原文地址:https://www.cnblogs.com/itcsl/p/7445748.html
Copyright © 2011-2022 走看看