一、题目描述
一个长度为n的序列,对于每个位置i的数ai都有一个优美值,其定义是:
找到序列中最长的一段[l,r],满足l<=i<=r,且[l,r]中位数为ai,则r-l+1就是ai的优美值。
我们比较序列中两个位置的数的大小时,以数值为第一关键字,下标为第二关键字比较。这样的话[l,r]的长度只有可能是奇数。
接下来有q个询问,每个询问[l,r]表示查询区间[l,r]内优美值的最大值。
二、输入格式
第一行输入n;
接下来一行 n 个整数,代表ai;
接下来一行为一个整数q,代表有q个区间
接下来q行,每行两个整数l,r(l<=r),表示区间的左右端点。
三、输出格式
对于每个区间的询问,输出答案。
四、样例输入
8
16 19 7 8 9 11 20 16
8
3 8
1 4
2 3
1 1
5 5
1 2
2 8
7 8
五、样例输出
7
3
1
3
5
3
7
3
六、数据范围与提示
对于30%的数据,满足n,q<=50;
对于70%的数据,满足n,q<=2000;
对于所有数据,满足n<=2000,q<=100000,ai<=200。
七、AC代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long n, a[2000 + 10], q;
long long left[4000 + 10], right[4000 + 10];
long long w[2000 + 10];
inline void yuchuli() {
scanf("%lld", &n);
for (register int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
}
for (register int i = 1; i <= n; ++i) {
memset(left, -1, sizeof(left));
left[n] = 0;
memset(right, -1, sizeof(right));
right[n] = 0;
int cnt = 0;
for (int j = i - 1; j >= 1; j--) {//对于i以前所有数
if (a[j] > a[i]) {//i左边有数比它大
cnt++;
}
if (a[j] <= a[i]) {//i左边有数比它小
cnt--;
}
left[n + cnt] = i - j;
}
cnt = 0;
for (register int j = i + 1; j <= n; ++j) {//对于i以后的数
if (a[j] >= a[i]) {//i右边有数比它大
cnt++;
}
if (a[j] < a[i]) {//i右边有数比它小
cnt--;
}
right[n + cnt] = j - i;
}
for (register int j = 1 - i; j <= i - 1; ++j) {
if (left[n + j] >= 0 && right[n - j] >= 0) {//代表left[n+j]和right[n-j]有赋值
w[i] = max(w[i], right[n - j] + 1 + left[n + j]);
}
}
}
}
int f[10000+5][21];
void yuchuli1() {//ST表的预处理
for (int i = 1; i <= n; i++) {
f[i][0] = w[i];
}
for (int j = 1; (1 << j) <= n; j++) {
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
}
int chazhao(int s, int t) {//ST表的查找
int k = 0;
while ((1 << k) <= t - s + 1) {
++k;
}
k--;
return max(f[s][k], f[t - (1 << k) + 1][k]);
}
int main() {
freopen("beautiful.in", "r", stdin);
freopen("beautiful.out", "w", stdout);
yuchuli();
yuchuli1();
scanf("%lld", &q);
while (q--) {
long long l, r;
scanf("%lld%lld", &l, &r);
printf("%d\n",chazhao(l,r));
}
return 0;
}