poj 3368(RMQ应用)

Frequent values
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 8555 Accepted: 3081

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 frequent value among the integers ai , ... , aj.

Input

The input consists of several test cases. Each test case starts with a line containing two integers n and q (1 ≤ n, q ≤ 100000). The next line contains n integersa1 , ... , an (-100000 ≤ ai ≤ 100000, for each i ∈ {1, ..., n}) separated by spaces. You can assume that for each i ∈ {1, ..., n-1}: ai ≤ ai+1. The following qlines contain one query each, consisting of two integers i and j (1 ≤ i ≤ j ≤ n), which indicate the boundary indices for the 
query.

The last test case is followed by a line containing a single 0.

Output

For each query, print one line with one integer: The number of occurrences of the most frequent value within the given range.

Sample Input

10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0

Sample Output

1
4
3

Source

分析:这题要求最长连续的数字。。。本来以为是出现次数最多,直接不会做阿。。。连续的话,就能转化为RMQ问题来搞
首先开一个数组a记录从左边到他本身有多少个连续的数,另一个数组b记录第i个数有几个和他相邻(待会计算位置用)
对于区间[l,r]
1.如果有a[r]>=r-l+1 即整个区间的数一样,直接返回区间长度
2.此时答案在左边,右边,和中间
         左边 b[l]-a[l]+1
         右边 a[r]
         中间 取区间 [l+b[l]-a[l]+1,r-a[r]]的最大值(用ST算法预处理)
代码:
#include<iostream>
#include<cstdio>
using namespace std;
const int mm=111111;
int f[mm][22],a[mm],b[mm],c[mm];
int i,j,k,n,q;
void dp()
{
    for(i=1;i<=n;++i)f[i][0]=a[i];
    for(j=1;(1<<j)<=n;++j)
        for(i=1;i+(1<<j)-1<=n;++i)
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int get(int l,int r)
{
    if(a[r]>=r-l+1)return r-l+1;
    int m=max(b[l]-a[l]+1,a[r]),k=0;
    l=l+b[l]-a[l]+1,r-=a[r];
    if(l>r)return m;
    while(l+(1<<k)<r-(1<<k)+1)++k;
    return max(m,max(f[l][k],f[r-(1<<k)+1][k]));
}
int main()
{
    while(scanf("%d",&n),n)
    {
        scanf("%d",&q);
        for(i=1;i<=n;++i)scanf("%d",&c[i]),a[i]=1;
        for(i=2;i<=n;++i)
            if(c[i-1]==c[i])a[i]+=a[i-1];
        for(b[n]=a[n],i=n-1;i>0;--i)
            if(c[i+1]==c[i])b[i]=b[i+1];
            else b[i]=a[i];
        dp();
        while(q--)scanf("%d%d",&i,&j),printf("%d\n",get(i,j));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值