题意:
给你一个序列,让你找出来最长的子序列,这个子序列中最大值减去最小值要小于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 ",ans); 43 } 44 return 0; 45 }