题目链接:点我啊点我啊
题目大意:
给出一个长度为 的非降序整数数列,有 个问题,每次询问区间 ,问在这个区间内,出现次数最多的那个数的次数是多少???
解题思路:
很明显是RMQ,但问题是这个题目询问的是出现最多的数的出现次数,那么我们就将RMQ的初始值设为每个数的出现次数,再用RMQ即可
代码思路:
因为我们初始的是每个数的出现次数,而且题目给的是非降序数列,所以我们对每个数所在的那一段连续相同的一段给出一些定义:
第几段数字
第
段数字出现了多少次
第
个数字处在第几段
第
段数字的起始位置
第
段数字的末尾位置
若询问区间
第
个数字在
内出现的次数为
第
个数字在
内出现的次数为
中间第
段到第
段的
的最大值就是RMQ
核心:灵活运用RMQ,在本题中就将每个数出现的次数作为RMQ的dp初始值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int q, len, a[N];
int cnt[N], num[N], lef[N], righ[N];
int dp[N][50];
void ST(int n, int d[]) {
for (int i=1; i<=n; i++) dp[i][0] = d[i];
for (int j=1; (1<<j) <= n; j++) {
for (int i=1; i+(1<<j)-1 <= n; i++) {
dp[i][j] = max(dp[i][j-1], dp[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(dp[l][k], dp[r - (1<<k)+1][k]);
}
int main() {
int n;
while(~scanf("%d", &n), n) {
memset(cnt, 0, sizeof(cnt));
scanf("%d%d", &q, &a[1]);
len = 1;
lef[len] = 1;
num[1] = len;
cnt[len] = 1;
for(int i=2; i<=n; i++) {
scanf("%d", &a[i]);
if(a[i] == a[i-1]) {
num[i] = len;
cnt[len]++;
} else {
righ[len] = i-1;
len++;
cnt[len] = 1;
lef[len] = i;
num[i] = len;
}
}
ST(len, cnt);
while(q--) {
int l, r, ans;
scanf("%d%d", &l, &r);
if(num[l] == num[r])
printf("%d\n", r-l+1);
else {
ans = 0;
if(num[l]+1 <= num[r]-1)
ans = RMQ(num[l]+1, num[r]-1);
ans = max(ans, max(righ[num[l]]-l+1, r-lef[num[r]]+1));
printf("%d\n", ans);
}
}
}
return 0;
}