这道题目是RMQ(Range Minimum/Maximum Query) 问题变形,寻找在区间内出现的最大频次。
用到动态规划
dp[ i] [j] =max(dp [i ] [j-1] ,dp[i +i<<(j-1) ] [j-1] ;
这道题的关键是如何构建一个dp数组。
我们可以将读取的数组num 变形。
所有相同的元素为 一组,用s[N]表示每组元素的起始下标,e[n]表示每组元素的结束下标,cnt【N】表示每组有多少个相同的元素。用pos[N]数组表示第 i 个元素属于第几个组。
int id=1; //id表示有多少组
s[1]=id;
for(i=1;i<=n;i++)
{
pos[i]=id;
cnt[id]++;
if(num[i]!=num[i+1]||i==n)
{
e[id]=i;
id++;
s[id]=i+1;
}
}
完整代码。
#include <iostream>
#include <stdio.h>
#include <memory.h>
using namespace std;
const int N=100010;
int cnt[N];
int pos[N];
int e[N];
int s[N];
int num[N];
int dp[N][20];
int pow[20];
int log2(int n)
{
int cnt=0;
while(n)
{ cnt++;
n>>=1;
}
return --cnt;
}
int max(int x,int y)
{ return x>y?x:y ; }
void RMQ(int n)
{
for(int i=1;i<=n;i++ )
{
dp[i][0]=cnt[i];
}
int temp=log2(n);
for(int j=1;j<=temp;j++)
{
for(int i=1;i+pow[j]-1<=n;i++)
dp[i][j]=max(dp[i][j-1],dp[i+pow[j-1]][j-1]);
}
}
int getmax(int a,int b)
{
int k=log2(b-a+1);
return max(dp[a][k],dp[b-pow[k]+1 ][k] );
}
int main()
{
int i,j,n,q;
for(i=1,pow[0]=1;i<20;i++)
pow[i]=2*pow[i-1];
while (cin>>n&&n)
{
memset(cnt,0,sizeof(cnt) );
cin>>q;
for(i=1;i<=n;i++)
{
cin>>num[i];
}
int id=1;
s[1]=id;
for(i=1;i<=n;i++)
{
pos[i]=id;
cnt[id]++;
if(num[i]!=num[i+1]||i==n)
{
e[id]=i;
id++;
s[id]=i+1;
}
}
RMQ(id);
int x,y;
while(q--)
{
scanf("%d%d",&x,&y);
if(pos[x]==pos[y] ) // in the same group
{
cout<<y-x+1<<endl;
}
else
{
int n1=e[pos[x]]-x+1;
int n2=y-s[pos[y]]+1;
int n3=0;
if( pos[y]-pos[x] >1) //统计pos[x] 与pos[y] 之间的最大值。
{
n3=getmax( pos[x]+1,pos[y]-1 );
}
cout<<( max( max(n1,n2) ,n3) )<<endl;
}
}
}
}