POJ2452 Sticks Problem
Time Limit: 6000MS MemoryLimit: 65536K
TotalSubmissions: 9607 Accepted: 2546
Description
Xuanxuan has n sticks of different length.One day, she puts all her sticks in a line, represented by S1, S2, S3, ...Sn.After measuring the length of each stick Sk (1 <= k <= n), she finds thatfor some sticks Si and Sj (1<= i < j <= n), each stick placed betweenSi and Sj is longer than Si but shorter than Sj.
Now given the length of S1, S2, S3, …Sn, you are required to find the maximumvalue j - i.
Input
The input contains multiple test cases. Eachcase contains two lines.
Line 1: a single integer n (n <= 50000), indicating the number ofsticks.
Line 2: n different positive integers (not larger than 100000), indicating thelength of each stick in order.
Output
Output the maximum value j - i in a singleline. If there is no such i and j, just output -1.
Sample Input
4
5 4 3 6
4
6 5 4 3
Sample Output
1
-1
Source
POJ Monthly,static
题意概述:
给定长度为n的序列s1…sn,求子序列si…sj使得子序列中最小值为si,最大值为sj。
解法一:
算法:RMQ(预处理)+枚举+二分(不加赘述 >_< )
时间复杂度:
1. RMQ预处理:O(NlogN)
2. 枚举+二分:O(NlogN)
解法二:*/
算法:RMQ(预处理)+单调栈
单调栈的基本操作:
维护栈使得栈中的元素具有单调性,即单调递增或递减。当即将入栈的元素不满足栈的单调性的时候,弹出栈顶元素知道新加入的元素仍然满足栈中元素的单调性。
解题步骤:
1. 首先RMQ预处理出每段区间的最大值及取最大值元素的位置
2. 按1到n的顺序将原序列中的元素依次加入到栈中,维护栈使得栈中元素单调递增
3. 当栈中某一元素被弹出时
记被弹出元素序号为i,当前即将加入的元素序号为j,根据栈的单调性可知sj为第一个比si小的元素,即si+1..sj-1都大于si。因此若子序列以si开头,则最大可能的右端点为sj-1
4. 用RMQ求区间[i+1..j-1]的最大值序号k,则以i开头的子序列最大长度为(k-i)
5. 持续更新子序列长度的最大值
应用此方法时应注意:
1. 为防止栈中元素都被弹出导致访问越界,应设定栈底元素值为-1(或更小的数)以保证其永远不会被弹出
2. 为防止栈中最后遗留一部分单调递增的元素,设原序列第n+1个元素(即sn+1)=0(但不要比栈底元素小)以保证原序列中每个元素都能被弹出
时间复杂度分析:
1. RMQ预处理:O(NlogN)
2. 单调栈:由于每个元素入栈一次退栈一次,退栈时查询区间最大值(即RMQ问题的询问)时间复杂度为O(1),所以单调栈总时间复杂度为O(N)
这种做法会比解法一快一点,而且代码好写一点哦~
附:代码(RMQ+单调栈)/*代码写的比较挫勿喷。。。*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<math.h>
usingnamespace std;
constint maxn=50000;
structnode
{
int xx,pp;
}rmq[maxn+100][50],stack[maxn+100],tmp;
nodemax(node x,node y)
{
if (x.xx>y.xx) return x;
else return y;
}
intn,tot,ans,a[maxn+10],tail,key,i,j;
intmain()
{
/*freopen("poj2452.in","r",stdin);
freopen("poj2452.out","w",stdout);*/
while (scanf("%d",&n)!=EOF){
ans=-1;
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
n++; a[n]=-1;
while ((1<<tot-1)<=n) tot++;
for (i=1;i<=n;i++){
rmq[i][0].xx=a[i];
rmq[i][0].pp=i;
}
for (i=1;i<=tot;i++)
for(j=1;j+(1<<i)-1<=n;j++)
rmq[j][i]=max(rmq[j][i-1],rmq[j+(1<<i-1)][i-1]);
/*for (i=1;i<=n;i++){
for (j=0;j<=tot;j++)
printf("%d",rmq[i][j].xx);
printf("\n");
}*/
stack[0].xx=-10; tail=0;
for (i=1;i<=n;i++){
if (i==n){
i=n;
}
while (stack[tail].xx>a[i]){
key=stack[tail].pp;
tot=1;
while((1<<tot)<=i-1-key) tot++;
tot--;
tmp=max(rmq[key][tot],rmq[i-(1<<tot)][tot]);
ans=max(ans,abs(tmp.pp-key));
tail--;
}
tail++;
stack[tail].xx=a[i];
stack[tail].pp=i;
}
if (ans>0)printf("%d\n",ans);
else printf("-1\n");
}
return 0;
}