zoukankan      html  css  js  c++  java
  • UVa 11235 Frequent values (RMQ && 区间出现最多次的数的次数)

    题意 : 给出一个长度为 n 的不降序序列,并且给出 q 个形如(L, R)的问询,问你这个区间出现的最多次的数的次数。

    分析 : 很自然的想到将区间“缩小”,例如1 1 2 3 3 3就可以变成2 1 3,构造出“数量数组”,这个数组实际上就是已经将原来区间分了块,但是问询的区间不可能就是这些“数量数组”构成的"块",不过先来想想问询的区间可不可能包含这里面的某些"块"?很显然是有可能的,那么从这些"块"中找出最大值显然就是经典的RMQ问题,用ST可以预处理并解决,但是对于不是这些"块"的该怎么办呢?还是从这些"块"入手,首先先给这些"块"升序编号,对于这些"块"我们可以知道在原来区间当中其左右端点,比如1 1 2 3 3 3,我们可以分成① ② ③三块,值分别是2、1、3,第一块的左端点是原区间的1,右端点是2,同理第二块左右端点都是3,第三块左右端点是4和5,这样做便构成了“数量数组”下标和原数组下标的一个映射,对于问询(L, R)我们能够知道L属于那一块,那么这一个块在(L,R)这个区间内贡献的相同的值的元素个数就是=>L所在的块的右端点 - L + 1(这里记作val_L),对于R也是同理可以得到val_R,那么最后答案就是 ans = max( RMQ(L和R之间包含的完整的块), max(val_L, val_R))。不过需要注意的是,如果此时L R同在一个块中的话,那么答案就是R-L+1了!

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5 + 10;
    int n, q, arr[maxn], dp[maxn][20];
    int cnt[maxn], L[maxn], R[maxn], num[maxn], tot;
    inline void RMQ_init()
    {
        for(int i=0; i<tot; i++) dp[i][0] = cnt[i];
        for(int j=1; (1<<j)<=tot; j++){
            for(int i=0; i+(1<<j)-1<n; i++){
                dp[i][j] = max(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
            }
        }
    }
    int RMQ(int L, int R)
    {
        if(L > R) return 0;
        int k = 0;
        while((1<<(k+1)) <= R-L+1) k++;
        return max(dp[L][k], dp[R-(1<<k)+1][k]);
    }
    int main(void)
    {
        while(~scanf("%d", &n) && n){
            scanf("%d", &q);
            memset(cnt, 0, sizeof(cnt));
            memset(L, 0, sizeof(L));
            memset(R, 0, sizeof(R));
            tot = 0;///表示"块"的个数
            int Last;
            for(int i=0; i<n; i++){///接下来对原区间的每一个元素进行映射处理
                scanf("%d", &arr[i]);
                if(i==0){
                    Last = arr[i];///记录当前“块”的具体值
                    L[tot] = i;///当前“块”的左端点是i
                }
                if(arr[i] == Last){///如果元素还是属于上一个“块”
                    cnt[tot]++;///“块”里面的元素+1
                    num[i] = tot;///当前下标i对应了tot这个块
                    R[tot] = i;///更新右界
                }else{
                    tot++;///有不同于之前的元素出现了,就相当于出现了新的“块”给其一个编号
                    cnt[tot]++;///tot“块”内元素+1
                    Last = arr[i];
                    num[i] = tot;
                    L[tot] = R[tot] = i;
                }
            }
            tot++;
            RMQ_init();///O(nlogn)的预处理
            while(q--){
                int Left, Right;
                scanf("%d %d", &Left, &Right);
                Left--, Right--;
                if(num[Left] == num[Right]){///如果同属一个“块”,则答案就是R - L + 1
                    printf("%d
    ", Right - Left + 1);
                    continue;
                }else{
                    int ans = max(RMQ(num[Left]+1, num[Right]-1),
                              max(R[num[Left]]-Left+1, Right-L[num[Right]]+1));
                    printf("%d
    ", ans);
                }
            }
    
        }
        return 0;
    }
    View Code
  • 相关阅读:
    js 为表格增加行 动态
    百度测试新搜索结果页面 改进灵感来自谷歌?
    多线程程序中使用fork的问题
    C++ struct和class的区别
    J2SE 5 HotSpot JVM 解释
    并行优化、xvout
    C++基础:纯虚函数和抽象类
    C++的四种cast
    logcat过滤输出
    C++虚函数和纯虚函数(2)
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/7400892.html
Copyright © 2011-2022 走看看