【Arc101D】Median of Medians

版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎前往zory.cf获得最佳体验 https://blog.csdn.net/Zory_Programmer/article/details/82077612

题意:给一个长度为 n 的数列,把每个子串的中位数组成新的序列,求其中位数
做法1:枚举 l r ,然后排序组成中位数,时间复杂度 O ( n 2 l o g 2 n )
做法2:枚举 n o w ,再枚举 l r ,统计比它小的数量考虑其贡献,时间复杂度 O ( n 3 )
正解(大小逻辑关系的运用不一定完全相同):
1. 二分答案,难点在于如何判定问题:答案是否 m i d
2. 不难想到,可以判定 m i d 的数字,其贡献 n ( n + 1 ) 4 + 1 ,对于每个区间,用类似的思路,考虑是否会被”堵住“, > ,用前缀和优化一下, ( a r a l 1 ) ( b r b l 1 ) > 0 ,为了方便, c l 1 < c r
3. 现在看起来复杂度是 O ( n 2 l o g 2 n ) ,但是显然可以用数据结构如树状数组优化,变成 O ( n l o g 2 2 n )

细节:爆int,一开始完全没注意到

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

namespace mine
{
    const int MAXN=110000;

    int n;

    int tr[2*MAXN];
    int lowbit(int x) {return x&-x;}
    void change(int d)
    {
        d+=MAXN;
        while(d<2*MAXN) tr[d]++,d+=lowbit(d);
    }
    int sum(int d)
    {
        d+=MAXN;
        int ans=0;
        while(d>=1) ans+=tr[d],d-=lowbit(d);
        return ans;
    }

    int a[MAXN],b[MAXN];
    int c[MAXN];

    typedef long long ll;//debug 爆int 
    bool check(int now)
    {
        for(int i=1;i<=n;i++) c[i]=c[i-1]+(a[i]<=now?1:-1);//1小于等于,-1大于

        memset(tr,0,sizeof tr);//debug
        change(c[0]);//debug 

        ll tot=0;//<=now的数,产生的贡献 
        for(int r=1;r<=n;r++)
        {
            //c[r]-c[l-1]>0 => c[l-1]<c[r] (l-1<r)
            tot+=sum(c[r]-1);
            change(c[r]);
        }
        return tot>=ll(n+1)*n/4+1;
    }
    void main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);

        int l=1,r=1e9,ans=-1;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(check(mid)) ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d",ans);
    }
};

int main()
{
    mine::main();
}

猜你喜欢

转载自blog.csdn.net/Zory_Programmer/article/details/82077612
今日推荐