题目链接:点我啊点我啊
题目大意:
给出一个长度为 n n n的非降序整数数列,有 q q q个问题,每次询问区间 [ l , r ] [l, r] [l,r],问在这个区间内,出现次数最多的那个数的次数是多少???
解题思路:
很明显是RMQ,但问题是这个题目询问的是出现最多的数的出现次数,那么我们就将RMQ的初始值设为每个数的出现次数,再用RMQ即可
代码思路:
因为我们初始的是每个数的出现次数,而且题目给的是非降序数列,所以我们对每个数所在的那一段连续相同的一段给出一些定义:
l
e
n
—
—
len——
len——第几段数字
c
n
t
[
i
]
—
—
cnt[i]——
cnt[i]——第
i
i
i段数字出现了多少次
n
u
m
[
i
]
—
—
num[i]——
num[i]——第
i
i
i个数字处在第几段
l
e
f
[
i
]
—
—
lef[i]——
lef[i]——第
i
i
i段数字的起始位置
r
i
g
h
[
i
]
—
—
righ[i]——
righ[i]——第
i
i
i段数字的末尾位置
若询问区间
[
L
,
R
]
[L, R]
[L,R]
第
L
L
L个数字在
[
L
,
R
]
[L, R]
[L,R]内出现的次数为
r
i
g
h
[
L
]
−
L
+
1
righ[L]-L+1
righ[L]−L+1
第
R
R
R个数字在
[
L
,
R
]
[L, R]
[L,R]内出现的次数为
R
−
l
e
f
[
R
]
+
1
R-lef[R]+1
R−lef[R]+1
中间第
n
u
m
[
L
]
+
1
num[L]+1
num[L]+1段到第
n
u
m
[
R
]
−
1
num[R]-1
num[R]−1段的
c
n
t
cnt
cnt的最大值就是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 = log(r - l + 1.0) / log(2.0);
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);
}
}
}
}