您的位置:首页 > 其它

POJ 2452 Sticks Problem(二分+RMQ)

2014-03-24 01:15 381 查看
POJ 2452 Sticks Problem(二分+RMQ)
http://poj.org/problem?id=2452


题意:
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.
分析:
我们从左到右依次扫描a[i],假设当前L为k,那么找到使得getMin(L,r)==L的最大r,那么区间[L,r]中的最大值位置即R=getMax(L,r)就是当L固定时的终点.所以当L固定时,最长区间为R-L+1.
找到使得getMin(L,r)==L的最大r,这个怎么求呢?这个的求法可以用二分法来求,因为如果存在r=100,使得上式成立,那么L<=r<100肯定都使上式成立.
注意本题输出的是R-L,而不是R-L+1.
AC代码:1766ms
<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 50000+100;
int a[MAXN];
int dmax[MAXN][20];//保存的是最大值的下标,且如果两个值相同,那么下标小的那个最大
int dmin[MAXN][20];//保存的是最小值的下标,且如果两个值相同,那么下标大的那个最小
int n;
int maxv(int i,int j)
{
    if(a[i]==a[j])
        return i<j?i:j;
    return a[i]<a[j]?j:i;
}
int minv(int i,int j)
{
    if(a[i]==a[j])
        return i<j?j:i;
    return a[i]<a[j]?i:j;
}
void initMax(int n,int d[])
{
    for(int i=1;i<=n;i++)dmax[i][0]=i;//dmax返回下标时,注意这里初始化的是i
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            dmax[i][j]=maxv(dmax[i][j-1] , dmax[i+(1<<(j-1))][j-1]);
}
int getMax(int L,int R)
{
    int k=0;
    while((1<<(k+1))<=R-L+1)k++;
    return maxv(dmax[L][k] , dmax[R-(1<<k)+1][k]);
}
void initMin(int n,int d[])
{
    for(int i=1;i<=n;i++)dmin[i][0]=i;
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            dmin[i][j]=minv(dmin[i][j-1] , dmin[i+(1<<(j-1))][j-1]);
}
int getMin(int L,int R)
{
    int k=0;
    while((1<<(k+1))<=R-L+1)k++;
    return minv(dmin[L][k] , dmin[R-(1<<k)+1][k]);
}
int get_r(int i)
{
    int l=i,r=n;
    while(r>l)
    {
        int mid=l+(r-l+1)/2;
        if(getMin(i,mid)==i)
            l=mid;
        else
            r=mid-1;
    }
    return l;
}
int main()
{

    while(scanf("%d",&n)==1)
    {
        if(n==0)
        {
            printf("-1\n");
            continue;
        }
        int ans=0;
         scanf("%d",&a[1]);
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]>a[i-1])
                ans=1;
        }
        if(ans==0)//非严格递减数列,不存在要求序列
        {
            printf("-1\n");
            continue;
        }
        initMax(n,a);
        initMin(n,a);
        int L,R,r;
        for(int i=1;i<=n;i++)
        {
            L=i;
            r=get_r(L);//找到使得getMin(L,r)==L的最大r
            R=getMax(L,r);
            ans=max(ans,R-L);
        }
        printf("%d\n",ans);
    }
    return 0;
}
</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: