[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

 

posted @ 2019-07-25 15:36  青君  阅读(161)  评论(0编辑  收藏  举报