优美值

优美值(思维题 (starstar ))

  • 一个长度为 (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
", ans);    
    }
}
int main(){
    Init();    
    Solve();
    return 0;
}
原文地址:https://www.cnblogs.com/hbhszxyb/p/13265884.html