优美值
优美值(思维题 \(\star\star \))
- 一个长度为 \(n\) 的序列,对于每个位置 \(i\) 的数 \(a_i\) 都有一个优美值,其定义是:找到序列中最 长的一段 \([l, r]\),满足 \(l ≤ i ≤ r\),且 \([l, r]\) 中位数为 \(a_i\)(我们比较序列中两个位置的数的大小时, 以数值为第一关键字,下标为第二关键字比较。这样的话 \([l, r]\) 的长度只有可能是奇数),\(r - l + 1\) 就是 \(i\) 的优美值。
- 接下来有 $Q $个询问,每个询问 \([l, r]\) 表示查询区间 \([l, r]\) 内优美值的最大值。
Input
- 第一行输入 \(n\) 接下来 \(n\) 个整数,代表 \(a_i\) 。
- 接下来一行为整数 \(Q\),代表有 \(Q\) 个区间需要查询。
- 接下来 \(Q\) 行,每行 两个整数 \(l, r(l ≤ r)\),表示区间的左右端点。
Output
- 对于每个区间的询问,输出答案。
Sample Input
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
Sample Output
7
3
1
3
5
3
7
3
Hint
- 对于 \(30\%\) 的数据,满足 \(n,Q ≤ 50\) 。
- 对于 \(70\%\) 的数据,满足 \(n,Q≤2000\) 。
- 对于所有数据,满足 \(n≤2000,Q≤100000,a_i≤200\) 。
- 来源:\(20180715\) ,推荐:洛谷P1114 “非常男女”计划
分析
- \(a[i]\) 要想成为中位数,则区间内比它小的数和比它大的数要一样多,我们从 \(i\) 开始向左扫描,如果遇到比 \(a[i]\) 大的数 \(cnt++\) ,遇到小于等于 \(a[i]\) 的数就 \(cnt--\) ,这样我们就很容易维护左边相互抵消后比 \(a[i]\) 大的区间长度,具体细节见代码,同样我们也能处理处右边的情况。
- 处理完两个数组后,要想 \(a[i]\) 成为中位数,则,如果左边大小抵消后比 \(a[i]\) 大的数还有 \(cnt\) 个,则,右边需要大小抵消后比 \(a[i]\) 大与等于的数应该有 \(-cnt\) 个,即右边比 \(a[i]\) 小的数有 \(cnt\) 个。
Code
#include <bits/stdc++.h>
const int maxn=2e3+5;
int n, a[maxn], w[maxn];
int L[maxn<<1],R[maxn<<1];//L[cnt]:当前处理数左边比它大的数-比它小的数个数为cnt的最大区间长度
void Init(){
scanf("%d", &n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
for(int i=1;i<=n;++i){//枚举每个数
memset(L,-1,sizeof(L)); L[n] = 0;
memset(R,-1,sizeof(R)); R[n] = 0;
int cnt = 0;
for(int j=i-1;j>=1;--j){
if(a[j] > a[i]) cnt++;//左边比a[i]大的+1
if(a[j] <= a[i]) cnt--;//左边比a[i]小的-1,相当于一大一小相互抵消
L[n + cnt] = i - j;//cnt有可能为负,所以整体+n
}
cnt = 0;
for(int j=i+1;j<=n;++j){
if(a[j] >= a[i]) cnt++;//右边比a[i]大的+1
if(a[j] < a[i]) cnt--;//右边比a[i]小的-1,相当于一大一小相互抵消
R[n + cnt] = j - i; //cnt有可能为负,所以整体+n
}
for(int j=1-i;j<=i-1;++j)//大小抵消后,a[i]为中位数,左端比a[i]大的为j,右边比它大的为-j
if(L[n + j] >= 0 && R[n - j] >= 0)//j表示比a[i]大,-j表示比a[j]小
w[i] = std::max(w[i], L[n + j] + 1 + R[n - j]);
}
}
void Solve(){
int Q;scanf("%d", &Q);
while (Q--){
int l, r;
scanf("%d%d", &l, &r);
int ans = 0;
for(int i=l;i<=r;++i)
ans = std::max(ans, w[i]);
printf("%d\n", ans);
}
}
int main(){
Init();
Solve();
return 0;
}
hzoi