zoukankan      html  css  js  c++  java
  • 优美值

    优美值(思维题 (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;
    }
    
  • 相关阅读:
    数据库管理 trove openstack
    Vmware 给虚拟机传脚本并执行
    Vmware 控制脚本
    python 脚本之 IP地址探测
    python 模块之-ffmpeg 中文参数对照表
    VMware ezmomi工具使用
    VS编译器从DLL导出模板类
    Qt5+VS2012编程
    Visual Studio 2012优化
    计算几何
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/13265884.html
Copyright © 2011-2022 走看看