University of Ulm Local Contest
Problem F: Frequent values
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.
题意:给出一个非递减的序列,找出某个区间出现次数最多的数的个数。
题目思路: RMQ + 边界的处理
解题方法:把序列分成t段(t等于序列不同数值的数个数),每段表示这个数出现的次数,例如tot[1]表示第一个数的个数,然后这个数组相当于RMQ的a数组。同时输入的时候需要记录每个数出现的左边界值numL[i]和右边界值numR[i]。最后只需要将区间划分为三段进行处理:1:numR[num[l]]-l+1(假如左边界的数是解);
2:r-numL[num[r]]+1(假如右边界的数是解);
3:RMQ(num[l]+1,num[r]-1) (解在区间的中间段);
特殊情况:如果左边界和右边界属于同一段,也就是说是同一个数,那么结果就直接求得:r-l+1;
代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define N 100010
int mm[N][30],num[N],numL[N],numR[N],tot[N];
void RMQ_DP(int n){
for(int i=1;i<=n;i++)
mm[i][0]=tot[i];
int nj=log(n+0.0)/log(2.0);
for(int j=1;j<=nj;j++){
int ni=n-(1<<j)+1;
for(int i=1;i<=ni;i++){
mm[i][j]=max(mm[i][j-1],mm[i+(1<<(j-1))][j-1]);
// mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ(int l,int r){
if(l>r) return 0;
int k=log(r-l+1.0)/log(2.0);
int Mm = max(mm[l][k],mm[r-(1<<k)+1][k]);
// int Mi = min(mi[l][k],mi[r-(1<<k)+1][k]);
return Mm;
}
int main(){
int n,q;
while(scanf("%d",&n)!=EOF){
if(n==0) break;
scanf("%d",&q);
memset(tot,0,sizeof(tot));
// memset(numL,0,sizeof(numL));
// memset(numR,0,sizeof(numR));
int c,t=0,tmp;
for(int i=1;i<=n;i++){
scanf("%d",&c);
if(i==1){
++t;
numL[t]=1;
numR[t]=0;
tmp = c;
}
if(c==tmp){
num[i]=t;
tot[t]++;
numR[t]++;
}else{
num[i]=++t;
tot[t]++;
numL[t]=numR[t]=i;
tmp=c;
}
}
RMQ_DP(t);
while(q--){
int l,r;
scanf("%d%d",&l,&r);
if(num[l]==num[r]){
printf("%d\n",r-l+1);
continue;
}
int ans=max( max(numR[num[l]]-l+1,r-numL[num[r]]+1),RMQ(num[l]+1,num[r]-1) );
printf("%d\n",ans);
}
}
return 0;
}