UVA 11235-Frequent values(RMQ)

Frequent values

题目意思:

给出一个非降序排列的整数数组A,对于一系列询问(L,R),求出AL~AR区间内出现次数最多的值出现的次数。

解题思路:

数组非降序,所以对整个数组进行游程编码。

所求的最大值是以下三个部分的最大值:

①从L到L所在的段的结束处的元素个数:right[L]-L+1

②从R到R所在的段的开始处的元素个数:R-left[R]+1

③中间第num[L]+1段到第num[R]-1段的cnt的最大值(RMQ)

注意!!这题输入输出要用C风格,C++会RE…Orz


#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define maxn 100100
#define ll long long
using namespace std;
int n,m;
int a[maxn],d[maxn][50];//给定的数组个RMQ用的DP数组
int value[maxn],cnt[maxn];//第i段的数值和出现次数
int num[maxn],lefts[maxn],rights[maxn];//当前下标表示的位置的所在段的编号和左右端点的位置
void RMQ_init()
{
    int i,j;
    for(i=1; i<=n; i++)
        d[i][0]=cnt[i];
    for(j=1; (1<<j)<=n; j++)
        for(i=1; i+(1<<j)-1<=n; i++)
            d[i][j]=max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}

int RMQ(int l,int r)
{
    int k=0;
    while((1<<(k+1))<=r-l+1) k++;
    return max(d[l][k],d[r-(1<<k)+1][k]);
}


int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("G:/x/read.txt","r",stdin);
    freopen("G:/x/out.txt","w",stdout);
#endif
    int q,i,m=1,l,ans=-1;
    bool flag=false;
    while(scanf("%d",&n),n)
    {
        scanf("%d",&q);
        memset(a,0,sizeof(a));
        memset(value,0,sizeof(value));
        memset(cnt,0,sizeof(cnt));
        memset(num,0,sizeof(num));
        memset(lefts,0,sizeof(lefts));
        memset(rights,0,sizeof(rights));
        memset(d,0,sizeof(d));
        for(i=1; i<=n; ++i)
        {
            scanf("%d",&a[i]);
            if(a[i]!=a[i-1]&&i!=1) flag=true;
            if(i==1)//a[1]特判一下
            {
                value[m]=a[i];
                ++cnt[m];
                num[i]=m;
                lefts[i]=i;
                l=i;
            }
            if(flag&&i!=1)
            {
                lefts[i]=i;
                l=i;
                ++m;
                num[i]=m;
                value[m]=a[i];
                ++cnt[m];
                for(int k=lefts[i-1]; k<i; ++k)
                    rights[k]=i-1;
                flag=false;
            }
            else
            {
                if(i!=1)
                {
                    ++cnt[m];
                    num[i]=m;
                    lefts[i]=l;
                    value[m]=a[i];
                }
                if(i==n)
                    for(int k=lefts[i-1]; k<=i; ++k)
                        rights[k]=i;
            }
        }
        RMQ_init();
        for(i=0; i<q; ++i)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            if(num[l]==num[r])  printf("%d\n",r-l+1);//特判,如果L和R在同一段中
            else
            {
                ans=max((rights[l]-l+1),(r-lefts[r]+1));
                if(num[l]+1<=num[r]-1)//必须保证RMQ区间左端点小于右端点
                {
                    int res=RMQ(num[l]+1,num[r]-1);
                    ans=max(ans,res);
                }
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}
/**
10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0
**/



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值