区间内最频繁数字计数

Author Avatar
Axell 1月 13, 2019
  • 在其它设备中阅读本文章

题目描述

给定n个整数,这n个整数已经从小到大排好序。

现在有m个询问,每次询问区间[a, b]内,最频繁出现的数字,出现了几次。

输入

输入n, m

接下来一行,输入n个整数vi

然后m行,每行输入一个区间a, b

输出

对于每个询问,输出最频繁出现的数字,出现了几次

样例输入

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

样例输出

1
4
3

提示

【样例说明】

[2, 3]里最频繁出现数字是-1和1,都出现了1次
[1, 10]里最频繁出现数字是1,出现了4次
[5, 10]里最频繁出现数字是10,出现了3次

【数据规模和约定】
1<=n, m<=100000 -100000<=vi<=100000

思路

因为序列是有序的,可以用T[i]表示,在第i的数之前(包括i)中,与i相同的值的个数
用RMQ的方式处理出区间最大值
每次统计时,先统计出一段以T[i]=1为起点的最大值,在与T[i]前的数取一个最大值即可

代码

#include <bits/stdc++.h>
using namespace std;

int n,m,l,r,a[100005],t[100005],last[100005],f[100005][18];

int getf(int l,int r){
    int len=r-l+1;
    int tmp=log(len)/log(2);
    int ret;
    if (t[l]==1){
        ret=max(f[l][tmp],f[r-(1<<tmp)+1][tmp]);
    }else{
        int la=last[l];
        if (la>=r) ret=r-l+1;
        else{
            ret=max(getf(la+1,r),la-l+1);
        }
    }
    return ret;
}

void initf(){
    for (int i=1;i<=n;++i) f[i][0]=t[i];
    int tt=log(n)/log(2);
    for (int j=1;j<=tt;++j){
        for (int i=1;i<=n-(1<<j)+1;++i){
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        }
    }
}

int main(){
    cin>>n>>m;
    for (int i=1;i<=n;++i) scanf("%d",&a[i]);
    for (int i=1;i<=n;++i){
        if (a[i]!=a[i-1]) t[i]=1;
        else t[i]=t[i-1]+1;
    }
    last[n]=n;
    for (int i=n-1;i>=1;--i){
        if (a[i]!=a[i+1]) last[i]=i;
        else last[i]=last[i+1];
    }
    initf();
    for (int i=1;i<=m;++i){
        scanf("%d %d",&l,&r);
        printf("%d\n",getf(l,r));
    }
    return 0;
}

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。

本文链接:https://hs-blog.axell.top/archives/67/