UVA - 11235 Frequent values 频繁出现的数值(RMQ)

大体题意:

给你n 个元素的非降序排列的数组,给你m 个询问i,j,求出 区间[i,j]内出现次数最多数的次数!

思路:

RMQ算法是求某个区间内的最小值或最大值!

这个问题关键是转换到RMQ问题上去!

因为数组呈非降序,所以所有相等的元素会聚在一起!

所以可以把数组分成一块一块的, val[i]表示第i块 数值是多少,cot[i]表示第i块出现了多少次!

num[p]表示数组位置p 属于哪一块,left[p],right[p]分别表示位置p所在块的  左边位置和右边位置!

那么只需统计 num[l] + 1 到 num[r] - 1 这些块中cot最大值是多少,在哪这个答案和边界进行比较!

边界时第L段 他有right[l]-l+1个     和R所在的段   有 r-left[r]+1个!

注意右边一定要大于左边的问题!

注意有个特殊情况,如果L和R在同一段,答案是R-L+1

详细见代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f;
int num[maxn],left[maxn],right[maxn],val[maxn],cot[maxn],a[maxn];
int n,m;
int cur;
int d[maxn][30];
void RMQ_init(){
    for (int i = 0; i < cur; ++i)d[i][0] = cot[i];
    for (int j = 1; (1<<j) <= cur; ++j)
        for (int i = 0; i+(1<<j)-1 < cur; ++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(){
    while(scanf("%d",&n) == 1 && n){
        scanf("%d",&m);
        memset(cot,0,sizeof cot);
        cur = 0;
        int last = inf;
        for (int i = 0; i < n; ++i) scanf("%d",&a[i]);
        for (int i = 0; i < n; ++i){
            left[i] = i;
            int j;
            for (j = i; j < n && a[j] == a[i]; ++j){
                val[cur] = a[i];
                cot[cur]++;
                num[j] = cur;
                left[j] = i;
            }
            int k = j-1;
            right[k] = k;
            for (; k >= i; --k){
                right[k] = j-1;
            }
            ++cur;
            i = j-1;
        }
        RMQ_init();
        for (int i = 0; i < m; ++i){
            int l,r;
            scanf("%d %d",&l,&r);
            l--;r--;
            if (num[l] == num[r]){
                printf("%d\n",r-l+1);
                continue;
            }
            int t1 = num[l]+1;
            int t2 = num[r]-1;
//            printf("t1 = %d,t2 = %d\n",t1,t2);

            int t_ans;
            if (t2 >= t1)
                t_ans = RMQ(t1,t2);
            else t_ans = 0;
//            printf("%d\n",right[l]);
            int ans = max(max(t_ans,right[l]-l+1),r-left[r]+1);
            printf("%d\n",ans);
        }
    }
    return 0;
}
/*
10 3
-1 -1 1 1 1 1 3 10 10 10
*/


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值