题目意思是找出一个给出的序列的子序列,使得其中的最大与最小值的差满足一定的范围。此种线性dp一般只有O(n)的算法才可以过,因此单调队列是最好的选择。发觉对单调队列的理解还不够啊。。。写的时候还是写成了一个自创的XX队列,只是水过了sample,看来还要继续努力~~
解法就是用两个单调队列,一个维护最小值,一个维护最大值。队列里装的是下标。但队列的“平衡”(队首元素之差不在目标范围内)被打破时,就要在两条队列中的队首中将所保存的标号较小的元素出队,直到恢复平衡。然后再计算此时的子串长度。
以下是参考yuan神的代码后写出来的:
- #include "stdio.h"
const int N=100100;
int a[N];
int queue1[N],queue2[N];
int n,m,k;- int max(int a,int b) {return a>b?a:b;}
- int main()
{ - while(scanf("%d%d%d",&n,&m,&k)==3)
{
int i,j;
int front1=0,rear1=0,front2=0,rear2=0;
int last1=0,last2=0;
int ans=0;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=n;i++)
{
while(front1<rear1 && a[queue1[rear1-1]]<=a[i]) rear1--;
queue1[rear1++]=i;
while(front2<rear2 && a[queue2[rear2-1]]>=a[i]) rear2--;
queue2[rear2++]=i;
while(a[queue1[front1]]-a[queue2[front2]]>k)
{
if(queue1[front1]<queue2[front2]) last1=queue1[front1++];
else last2=queue2[front2++];
}
if(a[queue1[front1]]-a[queue2[front2]]>=m)
ans=max(ans,i-max(last1,last2));
}
printf("%d/n",ans);
}
return 0;
}