题目链接:Frequent values
本来昨天下午就能搞出来的题硬是被一个极其微小的错误搞得花了两天时间才解决,说明自己还是功底不够,还有一方面是对RMQ的运用不那么熟练以至于出错需要大量时间找错误。
题意
给你一个非降序的整数数组,你的任务是对于一系列查询(i,j),回答 中出现次数最多的值所出现的次数。
题解
本题首先需要分析转换,如果按照正常暴力需要
时间复杂度。很明显是行不通的,所以需要另辟蹊径。
由于讨论的是出现次数最多的数的次数,所以我们可以先预处理,将相同的数字看成一段来解决。
以样例为例:
10 3
-1 -1 1 1 1 1 3 10 10 10
那么就可以将以上序列分为四段。
(1,2) , (2,4) , (3,3) , (4,2)
num[p]:存储位置p所在的段。
l[num[p]]:存储位置p所在的段的左端点序号。
r[num[p]]:存储位置p所在的段的右端点序号。
cnt[num[p]]:存储位置p所在的段的次数值。
这样就可以将查询的(L,R)分为三段:
1.从L到r[num[L]]所在段的元素个数(r[num[L]]-L+1)。
2.中间num[L]+1到num[R]-1段的cnt最大值。
3.从l[num[R]]到R所在段的元素个数(R-l[num[R]]+1)。
问题来了,中间段的值如何求?
可以看出中间段求最大值可以转化为区间求最大值,可以用RMQ问题的ST算法进行求解,预处理
时间复杂度,查询O(1)时间复杂度。
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10;
const int maxm=100+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int a[maxn],num[maxn],cnt[maxn],r[maxn],l[maxn];
int dp[maxn][50],n,pp;
void init_RMQ()
{
for(int p=1;p<=pp;p++) dp[p][0]=cnt[p];
for(int j=1;(1<<j)<=pp;j++)
for(int i=1;i+(1<<j)-1<=pp;i++)
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int RMQ(int L,int R)
{
if(num[L]==num[R]) return R-L+1;
int cntm=0,cntl=0,cntr=0;
if(num[L]+1<=num[R]-1)
{
int k=0;
while(1<<(k+1) <=(num[R]-num[L]-1) ) k++;
cntm=max(dp[num[L]+1][k],dp[num[R]-(1<<k)][k]);
}
cntl=r[num[L]]-L+1;
cntr=R-l[num[R]]+1;
return max(cntm,max(cntl,cntr));
}
int main()
{
int q;
while(~scanf("%d",&n) && n)
{
scanf("%d",&q);
memset(cnt, 0, sizeof(cnt));
memset(num, 0, sizeof(num));
memset(dp, 0, sizeof(dp));
a[0]=inf;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
pp=0;
for(int i=1;i<=n;i++)
{
if(a[i]==a[i-1])
{
num[i]=pp; r[pp]=i; cnt[pp]++;
}
else
{
pp++;
num[i]=pp;
r[pp]=i; l[pp]=i;
cnt[pp]=1;
}
}
init_RMQ();
while(q--)
{
int L,R;
scanf("%d%d",&L,&R);
printf("%d\n",RMQ(L, R));
}
}
}