您的位置:首页 > 其它

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

2016-03-14 22:09 344 查看

Subsequence

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 5495 Accepted Submission(s): 1809



[align=left]Problem Description[/align]
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.

[align=left]Input[/align]
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.

[align=left]Output[/align]
For each test case, print the length of the subsequence on a single line.

[align=left]Sample Input[/align]

5 0 0
1 1 1 1 1
5 0 3
1 2 3 4 5


[align=left]Sample Output[/align]

5
4




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

首先我们要明确几件事情

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: