巧妙利用单调队列(12哈工程多校)(3530)

来源:互联网 发布:辐射4xboxonex优化 编辑:程序博客网 时间:2024/05/16 04:36

Subsequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5495    Accepted Submission(s): 1809


Problem Description
There is a sequence of integers. Your task is to find the longest subsequence that satisfies the following condition: the difference between the maximum element and the minimum element of the subsequence is no smaller than m and no larger than k.
 

Input
There are multiple test cases.
For each test case, the first line has three integers, n, m and k. n is the length of the sequence and is in the range [1, 100000]. m and k are in the range [0, 1000000]. The second line has n integers, which are all in the range [0, 1000000].
Proceed to the end of file.
 

Output
For each test case, print the length of the subsequence on a single line.
 

Sample Input
5 0 01 1 1 1 15 0 31 2 3 4 5
 

Sample Output
54

这道题很有意思,需要巧妙地套用单调队列

首先我们要明确几件事情

1.假设我们现在知道序列(i,j)是符合标准的,那么如果第j+1个元素不比(i,j)最大值大也不比最小值小,那么(i,j+1)也是合法的

2.如果(i,j)不合法的原因是差值比要求小,那在(i,j)范围内的改动是无效的,需要加入j+1元素充当最大值或者最小值才可能获得合法的序列

3.假设序列(i,j)的差值比要求大,那么我们必须将其中的最大值或者最小值从序列中删除出去,才可能获得一个合法的序列,只往里加入元素是不可能令序列合法的

基于以上几点考虑,我们可以利用单调队列完成我们的算法。

设定一个变量ST作为当前合法序列的开端(对于一个序列(i,j),其对应的ST为i-1),初始值是0

设f[i]是以第i个元素结尾的最长合法序列长度,我们把i加入两个单调队列中维护,一个维护i之前的最小值,一个是最大值。

情况1.如果最大值和最小值的差值在范围之内,那么(ST,i)是合法序列,f[i]=i-ST。

情况2.如果差值比要求小,则没有以i结尾的合法序列,f[i]=0。

情况3.如果差值比要求大,那么需要删除最大值或者最小值,怎么删除?当然是删除最大值和最小值中靠前的那个,同时ST相应更新,直到情况1或者情况2。

理解:理解的难点在于每次加入新元素的时候对于两个单调队列的处理:ST是记录当前合法序列的开始的地方(ST这个临时变量很关键!!),每次求的其实都是从i开始向前的连续最大长度,单调队列维护的是i之前的最大值和最小值。(一开始想不通的点:如果前一个把D2全更新掉了,即前一个元素最大,对后一个元素产生的影响:无影响,因为从i向前必须得算上这个最大的元素,如果不行,那么避免不了,如果行,ST的值也不会随意变动)

/*------------------Header Files------------------*/#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <algorithm>#include <cstdlib>#include <ctype.h>#include <cmath>#include <stack>#include <queue>#include <deque>#include <map>#include <vector>#include <limits.h>using namespace std;/*------------------Definitions-------------------*/#define LL long long#define PI acos(-1.0)#define INF 0x3F3F3F3F#define MOD 10E9+7#define MAX 500050/*---------------------Work-----------------------*/int D1[100010],D2[100010],f[100010];void work(){int n,m,k;while(scanf("%d%d%d",&n,&m,&k)==3){int L1,L2,ST,R1,R2,ans;ans=L1=L2=ST=0,R1=R2=-1;for(int i=1;i<=n;i++){scanf("%d",&f[i]);while(L1<=R1&&f[D1[R1]]>=f[i]) R1--; //D1从小到大//把比它大的数都更新掉D1[++R1]=i;while(L2<=R2&&f[D2[R2]]<=f[i]) R2--; //D2从大到小//把比它小的数都更新掉D2[++R2]=i;while(f[D2[L2]]-f[D1[L1]]>k){if(D1[L1]<D2[L2]){ST=D1[L1];L1++;}else{ST=D2[L2];L2++;}}if(f[D2[L2]]-f[D1[L1]]>=m&&ans<i-ST) ans=i-ST;}printf("%d\n",ans);}}/*------------------Main Function------------------*/int main(){//freopen("test.txt","r",stdin);//freopen("cowtour.out","w",stdout);//freopen("cowtour.in","r",stdin);work();return 0;}



0 0