求解一段区间内出现次数最多的数出现的次数。由于数列已经是非降序排列,因此可以采用游程编码来进行预处理。游程编码(Run Length Ecoding),用count[i]表示第i段的数值出现的次数,num[p],left[p],right[p]分别表示位置p所在段的编号和左右端点的位置。处理结束后,这就是一个RMQ问题,使用ST算法加以解决即可。每次询问[l, r]的结果都是以下三个部分的最大值:从l到l所在段的结束处的元素个数,从r所在段的开始到r处的元素个数,中间第num[l]+1段到num[r]-1段的count的最大值。
AC代码:
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 100010;
const int INF = 0x3f3f3f3f;
int n,m,size;// the size of cnt[]
int dp[MAX][30];
int Count[MAX],num[MAX],Left[MAX],Right[MAX];
int Max(int a, int b){
return a > b ? a : b;
}
void RLE(){//游程编码
int pre = INF, cur = -1;//the index of current segment
int x, l;//l is the Left boundary of current segment
for(int i=0; i<n; i++){
scanf("%d",&x);
if(x == pre){
Count[cur]++;
num[i] = cur;
Left[i] = l;
}
else{
if(cur >= 0){
for(int j=l; j<=i-1; j++)
Right[j] = i-1;
}
cur++;// update the next segment
l = i;
num[i] = cur;
Left[i] = l;
Count[cur] = 1;
pre = x;
}
}
for(int i=l; i<n; i++)
Right[i] = n-1;
size = cur + 1;
}
void ST(){//sparse-table算法
int n = size;
for(int i=0; i<n; i++) dp[i][0] = Count[i];
int len = (int)(log((double)n)/log(2.0));
for(int j=1; j<=len; 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 Query(int l, int r){//查询最大值
if(l > r) return 0;
int k = (int)(log((double)(r - l + 1))/log(2.0));
return Max(dp[l][k], dp[r - (1<<k) + 1][k]);
}
int main(){
while(scanf("%d",&n) == 1 && n){
scanf("%d",&m);
RLE();
ST();
while(m--){
int l, r;
scanf("%d%d",&l,&r);
l--;
r--;
if(num[l] == num[r]) printf("%d\n",r - l + 1);
else{
int t1 = Right[l] - l + 1;
int t2 = r - Left[r] + 1;
int t3 = Query(num[l] + 1, num[r] - 1);
printf("%d\n",Max(t3, Max(t1, t2)));
}
}
}
return 0;
}