题目链接:http://poj.org/problem?id=3368
题意:求一段有序序列中某一区间段出现次数最高的数字的次数。
这题的关键在于它的序列是有序的,那么我们可以直接想到用Rmq。如果这个序列是无序的,我们可以先对它排序然后求解。
本题是较典型的RMQ,最小变为最大即可。left数组记录相同数字的起始位置。终止位置可以相减求出。
注意+-号的优先级比移位运算高,所以千万要加括号,不然会RE。深受其害。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;
#define Maxn 100100
//以点为基准
int num[Maxn];
int left[Maxn];
//以段为基准
int value[Maxn];
int total[Maxn];
int d[Maxn][40];
int n,q;
int l;
int seg;
void init(int a)
{
memset(total,0,sizeof(total));
seg = 1;
l = 1;
num[1] = seg;
left[1] = l;
value[1] = a;
total[1] = 1;
}
void rmq_init()
{
memset(d,0,sizeof(d));
for(int i=1;i<=seg;i++) d[i][0] = total[i];
for(int j=1;(1<<j)<=seg;j++)
{
for(int i=1;i + (1<<j) - 1<=seg;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 query(int s,int e)
{
if(num[s]>num[e]) return 0;
if(num[s] == num[e]) return e - s + 1;
else
{
int temp = max(total[num[s]] - (s - left[s]),(e - left[e]) + 1);
if(num[e]-1 < num[s] + 1) return temp;
return max(temp,rmq(num[s]+1,num[e]-1));
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int a;
int s,e;
while(scanf(" %d",&n)!=EOF && n!=0)
{
scanf(" %d",&q);
scanf(" %d",&a);
init(a);
for(int i=2; i<=n; i++)
{
scanf(" %d",&a);
if(a != value[seg])
{
seg++;
l = i;
}
num[i] = seg;
left[i] = l;
value[seg] = a;
total[seg]++;
}
rmq_init();
for(int i=1;i<=q;i++)
{
scanf(" %d %d",&s,&e);
printf("%d\n",query(s,e));
}
}
}