Subsequence HDU - 3530

题意:

给你一个序列,让你找出来最长的子序列,这个子序列中最大值减去最小值要小于k大于等于m

 

题解:

维护两个单调序列,一个递增一个递减。这样可以对于序列中的每一个位置。找到包含这个位置的最长满足题意得序列

具体见代码

 

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <iostream>
 5 #include <algorithm>
 6 using namespace std;
 7 typedef long long ll;
 8 typedef unsigned long long ull;
 9 const int inf=0x3f3f3f3f;
10 const ll INF=0x3f3f3f3f3f3f3f3fll;
11 const int maxn=100010;
12 int num[maxn],Q1[maxn],Q2[maxn];
13 int n,m,k;
14 int main()
15 {
16     while(scanf("%d%d%d",&n,&m,&k)!=-1)
17     {
18         for(int i=1; i<=n; i++) scanf("%d",&num[i]);
19         int s1=0,e1=0,s2=0,e2=0,ans=0,pos=0;
20         /*
21         因为Q1是递减序列(都是按照下标从小到大)
22         Q2是递增序列
23         
24         因为如果s1和s2的位置发生变化,那就意味着Q1[s1]-Q2[s2],也就是维护到现在的序列最小值和最大值之差已经不满足题意
25         那么就需要s1或者s2移动,那个移动更好呢?因为我们更新答案是i-pos,所以pos越小越好,那么就Q1[s1]和Q2[s2]中
26         小的那个。
27         又因为有s1<e1和s2<e2得条件判断,所以不会出现s2>e2和s1>e1情况
28         */
29         for(int i=1; i<=n; i++)
30         {
31             while(s1<e1&&num[Q1[e1-1]]<num[i]) e1--;  //注意这个s1<e1的判断是在左端同时控制这个Q1序列
32             while(s2<e2&&num[Q2[e2-1]]>num[i]) e2--;
33             Q1[e1++]=i;
34             Q2[e2++]=i;
35             while(s1<e1&&s2<e2&&num[Q1[s1]]-num[Q2[s2]]>k)
36             {
37                 if(Q1[s1]<Q2[s2]) pos=Q1[s1++];
38                 else pos=Q2[s2++];
39             }
40             if(s1<e1&&s2<e2&&num[Q1[s1]]-num[Q2[s2]]>=m) ans=max(ans,i-pos);
41         }
42         printf("%d\n",ans);
43     }
44     return 0;
45 }

 

posted @ 2020-06-17 15:06  kongbursi  阅读(142)  评论(0编辑  收藏  举报