poj2452

题意:给你一组数a[n],求满足a[i] < a[k] < a[j] (i <= k <= j)的最大的j-i。


解法一:
先记录每一位数后面连续大于这个数的长度,然后再这个长度里找最大的数,这样可求得最大的区间



#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;
int main()
{
    int a[5005],dis[50005];
    int n,maxn,flag,ans;
    while(scanf("%d",&n)!=EOF)
    {
        ans=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            dis[i]=1;
        }
        dis[n+1]=-1;
        for(int i=n;i>=0;i--)
        {
            while(a[i]<a[i+dis[i]])
                dis[i]+=dis[i+dis[i]];
        }
        for(int i=1;i<=n;i+=flag+1)
        {
            maxn=flag=-1;
            for(int j=0;j<dis[i];j++)
            {
                if(a[i+j]>maxn)
                {
                    maxn=a[i+j];
                    flag=j;
                }
            }
            if(flag>ans)
                ans=flag;
        }
        if(ans)
            printf("%d\n",ans);
        else
            printf("-1\n");
    }
    return 0;
}


解法二:

  1. RMQ + 二分。 
  2. 枚举i,利用二分求出a[i]右边第一个小于a[i]的数的位置k, 
  3. 再求出[i, k]中最大值的位置j,若a[j] > a[i],则更新结果。
#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <algorithm>  
#include <cmath>  
  
using namespace std;  
  
const int maxn = 50010;  
int n, len[maxn];  
// 分别存储的是最大值和最小值的下标   
int minl[maxn][20], maxl[maxn][20];  
  
  
int _min(int l, int r)  
{  
    if (len[l] < len[r]) return l;  
    return r;  
}  
  
int _max(int l, int r)  
{  
    if (len[l] > len[r]) return l;  
    return r;  
}  
  
void init()  
{  
    for (int i = 1; i <= n; ++i)  
        minl[i][0] = maxl[i][0] = i;  
    for (int j = 1; (1<<j) <= n; ++j)  
    {  
        for (int i = 1; i + (1<<j) - 1 <= n; ++i)  
        {  
            minl[i][j] = _min(minl[i][j-1], minl[i+(1<<(j-1))][j-1]);  
            maxl[i][j] = _max(maxl[i][j-1], maxl[i+(1<<(j-1))][j-1]);  
        }  
    }  
}  
  
int minrmq(int l, int r)  
{  
    int k = (int)(log(double(r) - l + 1) / log(2.0));  
    return _min(minl[l][k], minl[r+1-(1<<k)][k]);  
}  
  
int maxrmq(int l, int r)  
{  
    int k = (int)(log(double(r) - l + 1) / log(2.0));  
    return _max(maxl[l][k], maxl[r+1-(1<<k)][k]);  
}  
  
int bsearch(int x, int l, int r)  
{  
    while (l <= r)  
    {  
        if (l == r) return l;  
        int m = (l + r) >> 1;  
        if (len[x] < len[minrmq(l, m)])  
            l = m + 1;  
        else r = m;  
    }  
}  
  
void work()  
{  
    int ans = 0;  
    for (int i = 1; i + ans < n; ++i)  
    {  
        int r = bsearch(i, i + 1, n);  
        int k = maxrmq(i, r);  
        if(len[k] > len[i])  
            ans = max(ans, k - i);  
    }  
    if (ans == 0) printf("-1\n");  
    else printf("%d\n", ans);  
}  
  
int main()  
{  
    while (scanf("%d", &n) != EOF)  
    {  
        for (int i = 1; i <= n; ++i)  
            scanf("%d", &len[i]);  
        init();  
        work();  
    }  
    return 0;  
}  




害羞

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值