RMQ poj3368

题目链接

题目大意

  有一个数字串长度为n,输入顺序为非递减,给出一个区间[L,R],要求算出区间中某个出现次数最多的数,答案为它出现的次数。

  1. N<105 , 区间数cas<105

  2. 多组测试,以0结尾

 

解题思路

  因为数组是非递减序列,所以可以将数组分段。(也叫游程编码,Run Length Encoding RLE)

  1.扫描一遍数组,求如下:

   - count[ i ] : 表示第 i 段中数字出现的次数总和

   - num[ p ] : 表示位置P所在段的编号

   - Left [ p ] , Right[ p ] : 分别表示P所在段的左右端点的位置(这里的位置都是指的在原数组中的位置)

  2. 根据count 数组我们可以建立RMQ,每一个数据段都有一个相应出现的次数。

  3. 对于给出的区间 [ L, R],按照如下进行求解:

   -num[L] = num[R] : 表示给出的区间在一个段落,那么ans = R - L +1;

   - 否则 结果至少是L到L所在段的最右端距离 和 R所在段的最左端到R的距离 的最大值,ans = max(Right[L]-L+1, R-Left[R]+1);

   - 如果 num[R] > num[L]+1 : 那么说明这个区间中至少有3个段,所以ans = max(ans, RMQ(num[L]+1, num[R]-1)), 在RMQ中找出中间段落的最大值区间为:num[L]+1 到 num[R]-1.

代码献上

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

using namespace std;

const int MAX_N = 100000;

int a[MAX_N+1],coun[MAX_N+1],num[MAX_N+1];
int Left[MAX_N+1],Right[MAX_N+1],d[MAX_N][20];

//这里采用Sparse-Table 基于稀疏表的RMQ
void RMQ_init(int n)
{
    for(int i = 0; i<n; i++) d[i][0] = coun[i];
    for(int j = 1; (1<<j)<=n; j++)
        for(int i = 0; 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()
{
    int n,cas;
    while(1)
    {
        scanf("%d",&n);
        if(n == 0) break;
        scanf("%d",&cas);
        for(int i = 0; i<n; i++)
            scanf("%d",&a[i]);

        int total = 0;
        //一遍扫描
        for(int i = 0; i<n; )
        {
            int s = upper_bound(a,a+n,a[i]) - lower_bound(a,a+n,a[i]);
            coun[total] = s;
            for(int j = i ; j<i+s; j++){
                num[j] = total;
                Left[j] = i;
                Right[j] = i+s-1;
            }
            i = i+s;
            total++;
        }
        //建立RMQ
        RMQ_init(total);

        //求解
        for(int i = 0; i<cas; i++){
            int l,r;
            scanf("%d%d",&l,&r);
            l = l-1;
            r = r-1;
            int ans;
            if(num[l] == num[r]) ans = r-l+1;
            else ans = max(Right[l]-l+1, r-Left[r]+1);
            if(num[r]>num[l]+1) ans = max(ans, RMQ(num[l]+1, num[r]-1));
            printf("%d\n",ans);
        }
    }
    return 0;
}
时间: 2024-11-08 21:41:56

RMQ poj3368的相关文章

ACM训练大纲

1. 算法总结及推荐题目 1.1 C++ STL ? STL容器: set, map, vector, priority_queue, queue, stack, deque, bitset? STL算法: sort, unique, nth_element, reverse, rotate, next_permution, find, for_each, count, lower_bound, max, swap, random_shuffle 1.2 基本算法 ? 枚举: poj1753,

ACM学习资料整理

ACM学习资料整理 声明:参考泥瓦匠BYSocket.POJ题目分类推荐 (很好很有层次感)整理所得 1 推荐题库 ?http://ace.delos.com/usaco/ 美国的OI 题库,如果是刚入门的新手,可以尝试先把它刷通,能够学到几乎全部的基础算法极其优化,全部的题解及标程还有题目翻译可以baidu 一个叫NOCOW 的网站.   ?http://livearchive.onlinejudge.org/ 上面有全部的赛区真题,绝大部分都可以提交,不适合当题库刷,不过在这里找题非常方便.

POJ3368 Frequent values(RMQ线段树)

题目大概说给一个递增序列,询问区间出现最多的数. 用莫队算法比较直观,虽然应该会T..好像也可以主席树..不过题目给的序列是有序的,因而相同的数会聚在一起. 考虑把序列分成一段一段,使每段都包含极大的相同的数字 这样对于每一个区间查询: 可能这个区间左边或右边没有包含完整的一段,而其长度在段里对左或右端点进行二分查找就知道了 而除去两边不完整的,还要求出中间若干完整段的最大长度,这个就是用RMQ来快速解决了 于是这题就能这样解决了. 1 #include<cstdio> 2 #include&

[poj3368]Frequent values(rmq)

题意:给出n个数和Q个询问(l,r),对于每个询问求出(l,r)之间连续出现次数最多的次数. 解题关键:统计次数,转化为RMQ问题,运用st表求解,注意边界. 预处理复杂度:$O(n\log n)$ 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cmath> 6 #include<iostream>

POJ3368(RMQ)

Frequent values Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the most freque

RMQ //poj3264,poj3368

http://poj.org/problem?id=3264 #include<iostream> #include<cstdio> #include<string> #include<cmath> #include<cstring> #define M 1000000 + 50 using namespace std; int a[M]; int maxs[M][100]; int mins[M][100]; int QueryMax(int

POJ3368Frequent values[RMQ 游程编码]

Frequent values Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 17581   Accepted: 6346 Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries cons

POJ3368---Frequent values(分组处理+RMQ)

Language: Frequent values Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 14377 Accepted: 5244 Description You are given a sequence of n integers a1 , a2 , - , an in non-decreasing order. In addition to that, you are given several queries

dutacm.club 1094: 等差区间(RMQ区间最大、最小值,区间GCD)

1094: 等差区间 Time Limit:5000/3000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)Total Submissions:655   Accepted:54 [Submit][Status][Discuss] Description 已知一个长度为 n 的数组 a[1],a[2],-,a[n],我们进行 q 次询问,每次询问区间 a[l],a[l+1],-,a[r?1],a[r] ,数字从小到大