bnuoj 2571Sticks Problem

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 that for some sticks Si and Sj (1<= i < j <= n), each stick placed between Si 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 maximum value j - i.

Input

The input contains multiple test cases. Each case contains two lines. 
Line 1: a single integer n (n <= 50000), indicating the number of sticks. 
Line 2: n different positive integers (not larger than 100000), indicating the length of each stick in order.

Output

Output the maximum value j - i in a single line. 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
题目意思:求出最长序列长度,要求在最长序列中中间的值要比这一段内最左边的值大比最右边的值要小,中间可以是无序的。最大长度大于1的则输出最大长度减1,否则输出-1.
解题:用一个结构体记录可能存在最长长度len,最两边的位置L,R和最大值的位置I。先以起点最小值开始记,每个点都要大于起点,同时记下最大值的位I,当小于起点时,也就小于当前段的起点开始的所有点值直到当前点,那么就以当前点为下一个起点开始记,作下一段。在开始计算长度时一定要注意判断条件。这一段的最大值是最右边时那么这一段可以直接与maxlen作比较。
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 50000
struct duan
{
    int L,R,len,I;//L和R为这一段的最左和右,len是这一段长度,I为这一段的最大值位置以位置小为优先
};
int cmp(duan a,duan b)
{
    return a.len>b.len;
}
int num[N+5];
int main()
{
    int n,dn,max;
    duan d[N+5];
    while(scanf("%d",&n)>0)
    {
        d[1].len=d[1].L=d[1].R=1; dn=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
            if(i==1){max=num[i];d[1].I=i;}
            else
             if(num[d[dn].L]<num[i])
              {
                  d[dn].R=i; d[dn].len=i-d[dn].L+1;
                  if(max<num[i])
                  {max=num[i]; d[dn].I=i;}
              }
              else
              {
                  dn++; d[dn].L=d[dn].R=i; d[dn].len=1;
                  max=num[i]; d[dn].I=i;
              }
        }
          sort(d+1,d+dn+1,cmp);
          int maxlen=0,tn=dn,I,tI;
        for(int i=1;i<=dn;i++)
        if(d[i].len>=2&&d[i].len-1>maxlen)
        {
            I=d[i].I;
            if(num[I]<num[d[i].R]||I==d[i].R)
            {
                if(maxlen<d[i].len-1) maxlen=d[i].len-1;
                if(i<tn) i=tn;
            }
            else
            {
                if(maxlen<I-d[i].L) maxlen=I-d[i].L;
                int j,v;
                while(maxlen<d[i].R-I-1&&d[i].R-I>=2)
                {
                    for(j=I+1;num[I]==num[j]&&j<=d[i].R;j++){ }
                    if(d[i].R-j<1||d[i].R-j<=maxlen) break;
                    max=num[j];tI=j;
                    for(v=j+1;num[j]<num[v]&&v<=d[i].R;v++)
                        if(max<num[v]){max=num[v]; tI=v;}
                        v--; I=v;
                    if(v-j>maxlen)
                    {
                        dn++; d[dn].L=j; d[dn].I=tI;
                        d[dn].R=v; d[dn].len=v-j+1;
                    }
                }
            }
        }
        printf("%d\n",maxlen>0?maxlen:(-1));
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值