巧妙利用单调队列(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; }
相关文章推荐
- Fiddler
- 20135323符运锦----第四周:扒开系统调用的“三层皮”
- 转:Automatic Layout Groups
- 启动画面的细节处理
- 开发中遇到的坑
- java中synchronized锁定对象问题
- POJ 2155 Matrix(二维树状数组)
- 环信--即时通讯平台
- jQuery省市区三级联动插件
- ANDROID SHAPE画圆形背景_ANDROID实现角标布局
- 找工作感想
- 图片保存1
- 第56课:Spark SQL和DataFrame的本质
- 设计模式学习笔记——模板方法模式
- Problem E: 结构体---点坐标结构体
- 关于时间的思考
- 对接联调是一个情商活
- C++的异常安全性
- HDU3374
- RedHat升级Python2.6到Python3.4.3版本