题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3530
题意
给出一个数列 ai ,及一个范围 [m,k] ,求这个数列中所有连续的区间的最大值与最小值之差在[m,k]中,的区间长度最大是多少。
思路(单调队列+尺取法)
满足某一要求,求最大或最小区间长度很容易想到尺取法,而怎么快速求某一区间的最大最小值,很容易想到RMQ之类的算法,比如线段树、ST表、树状数组等,但是尺取法本身就是区间滑动的过程,所以也可以通过单调队列顺便求出区间的最大值和最小值,总体思路没什么问题,需要注意一个问题:左右端点如何滑动。
设左右端点为L,R,如果当前区间满足条件,那么应该尽可能的扩大区间,直到不能扩大为止,这个之后缩小左端点,L++直到满足条件,对每一次满足条件后的区间长度求一次max。最大值和最小值分别用两个单调队列记录。
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000009
#define ll long long
#define inf 1000000009000000000
#define IOS ios::sync_with_stdio(false)
int ff[maxn];
pair<int,int> dq1[maxn],dq2[maxn];
int main()
{
IOS;
int n,m,k;
while(cin>>n>>m>>k)
{
for(int i=1; i<=n; i++)
cin>>ff[i];
int L=1,ans=0;
int le1=1,ri1=1;
int le2=1,ri2=1;
for(int i=1; i<=n; i++)
{
if(le1==ri1)
dq1[ri1++]=make_pair(i,ff[i]);
else
{
while(le1!=ri1&&dq1[ri1-1].second>ff[i])
ri1--;
dq1[ri1++]=make_pair(i,ff[i]);
}
if(le2==ri2)
dq2[ri2++]=make_pair(i,ff[i]);
else
{
while(le2!=ri2&&dq2[ri2-1].second<ff[i])
ri2--;
dq2[ri2++]=make_pair(i,ff[i]);
}
//cout<<dq1[le1].second<<" w "<<dq2[le2].second<<" l r "<<le2<<" "<<ri2<<endl;
while(le1!=ri1&&le2!=ri2&&abs(dq1[le1].second-dq2[le2].second)>k)
{
L++;
if(le1!=ri1&&dq1[le1].first<L)
le1++;
if(le2!=ri2&&dq2[le2].first<L)
le2++;
}
if(le1!=ri1&&le2!=ri2&&abs(dq1[le1].second-dq2[le2].second)>=m)
{
ans=max(ans,i-L+1);
//cout<<"asn="<<ans<<endl;
}
//cout<<L<<" "<<i<<endl;
}
cout<<ans<<"\n";
}
return 0;
}