zoukankan      html  css  js  c++  java
  • [BZOJ1303][CQOI2009]中位数图

    Solution

      有点意思的思维题。

      首先考虑到一个满足b是中位数的子序列中大于b和小于b的数字的个数一定是相等的。

      设b在排列中的位置为p,可以对于每一个在p左边的位置i求出序列[i,p-1]中小于b的个数和大于b的个数,记为cnt1和cnt2;同理对于每一个在p右边的位置j求出序列[p+1,j]求出相应的cnt1和cnt2。

      如果直接枚举i,j判断两者的cnt1和cnt2加起来是否相等是n^2的,会T。

      cnt1和cnt2有两维,不方便比较,稍加思考会发现其实可以转化成一维。

      即:

      $cnt1+cnt1'=cnt2+cnt2'$ $Longleftrightarrow$ $cnt1-cnt2=cnt2'-cnt1'$

      所以我们只需要记个差值就可以了。

      于是按照套路,先把左端点的差值存multiset,然后枚举右端点,O(logn)查询即可。

      但是这样计算的只是跨过p位置的连续子序列,不要忘了加上以p为右端点的左边子序列,和以p为左端点的右边子序列。

      还有发现差值的范围在-N~N之间,于是multiset都不用了,开个桶就好了(我真是个zz)

      于是O(n)AC了这题。

      Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5,D=1e5;//有负数下标,整体加D 
    int n,b,p,l,r,cnt1,cnt2,ans,a[N],s[N<<1];
    int main(){
        cin>>n>>b;
        for(int i=1;i<=n;++i){
            cin>>a[i];
            if(a[i]==b) p=i,++ans;
        }
        for(int i=p-1;i>=1;--i){
            a[i]<b?++cnt1:++cnt2;
            ++s[cnt1-cnt2+D];
            ans+=cnt1==cnt2;
        }
        cnt1=cnt2=0;
        for(int i=p+1;i<=n;++i){
            a[i]<b?++cnt1:++cnt2;
            ans+=(cnt1==cnt2)+s[cnt2-cnt1+D]; 
        }
        cout<<ans<<endl;
        return 0;
    }
    BZOJ1303
  • 相关阅读:
    寄存器基础知识
    基础知识
    架构
    Mac下Apache服务器的初步搭建
    ios字体简单设定
    xcode中自定义log打印
    jQuery打印插件
    ionic3生命周期钩子
    ES5 数组方法map
    $compile的妙用
  • 原文地址:https://www.cnblogs.com/gosick/p/11244642.html
Copyright © 2011-2022 走看看