题意:你被给予了一个非单调递减的n个数字的序列a1, a2, ..., an。除此之外,你被给予了q个询问,每个询问由i, j(1 <= i <= j <= n)。求这个区间内出现最多的数的次数。
分析:这是一个非单调递减的序列,比如样例中的-1 -1 1 1 1 1 3 10 10 10,我们可以得到每个连续相等区间的数字次数为2 4 1 3,这个序列可以用RMQ维护。但是询问中的[L, R]不一定是正好在某个连续区间的边界,因此,我们可以求出左右两个多出来的区间部分的数的次数,中间连续的区间再用RMQ查询。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 100005;
const int M = 18;
int f[N], val[N], pos[N];
int l[N], r[N];
int g[N], idx;
int dp[N][M];
int n, q;
void init()
{
for(int j = 0; j < M; ++j)
for (int i = 1; i + (1 << j) - 1 <= idx; ++i)
{
if (!j) dp[i][j] = g[i];
else dp[i][j] = max(dp[i][j - 1], dp[i + (1 << j - 1)][j - 1]);
}
}
int query(int L, int R)
{
int p = pos[L], q = pos[R];
if (p == q)
{
return R - L + 1;
}
else
{
int k1 = r[p] - L + 1;
int k2 = R - l[q] + 1;
++p, --q;
if (p <= q)
{
int len = q - p + 1;
int t = log((double)len) / log((double)2);
return max(max(k1, k2), max(dp[p][t], dp[q - (1 << t) + 1][t]));
}
else
{
return max(k1, k2);
}
}
}
void clear()
{
idx = 0;
memset(dp, 0, sizeof dp);
}
int main()
{
while (scanf("%d", &n) != EOF)
{
if (n == 0) break;
scanf("%d", &q);
for (int i = 1; i <= n; ++i) scanf("%d", &val[i]);
int i;
for (i = 1; i <= n; ++i)
{
if (val[i] == val[i - 1] && i - 1 != 0)
{
f[i] = f[i - 1] + 1;
}
else
{
l[idx] = i - f[i - 1], r[idx] = i - 1;
g[idx] = f[i - 1];
f[i] = 1;
++idx;
}
pos[i] = idx;
}
l[idx] = i - f[i - 1], r[idx] = i - 1;
g[idx] = f[i - 1];
init();
int l, r;
while (q--)
{
scanf("%d%d", &l, &r);
printf("%d
", query(l, r));
}
clear();
}
return 0;
}