P1627 [CQOI2009]中位数

题目描述

给出1~n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。

输入格式

第一行为两个正整数n和b,第二行为1~n的排列。

【数据规模】

对于30%的数据中,满足n≤100;

对于60%的数据中,满足n≤1000;

对于100%的数据中,满足n≤100000,1≤b≤n。

输出格式

输出一个整数,即中位数为b的连续子序列个数。

输入输出样例

输入 #1
7 4
5 7 2 4 3 1 6 
输出 #1
4

思路:

把中位数出现的位置设为pos,比中位数大的设为1,小的设为-1.

lsum[i]表示i到pos的和,即1的个数和-1的个数差

rsum[i]表示pos到i的和,同理。

l[sum[i]]表示pos左边和为sum出现的次数

r[sum[i]]表示pos右边和为sum出现的次数

由于c++数组不能开负下标,所以需要向右偏移n

如果l[i]=r[-i]就可以将ans+=l[i]*r[-i].

代码:

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

const int N=400010;

int b,n,flag,x,ans=0;
int l[N],r[N],a[N],sum[N/2];

int main () {
    scanf("%d%d",&n,&b);
    for(int i=1; i<=n; i++) {
        scanf("%d",&x);
        if(x==b) {
            flag=i;
            a[i]=0;
        } else if(x>b)
            a[i]=1;
        else
            a[i]=-1;
    }
    l[n]=1;
    r[n]=1;
    for(int i=flag-1; i>=1; i--) {
        sum[i]=sum[i+1]+a[i];
        l[sum[i]+n]++;
    }
    for(int i=flag+1; i<=n; i++) {
        sum[i]=sum[i-1]+a[i];
        r[sum[i]+n]++;
    }
    for(int i=0; i<=2*n-1; i++)
        ans+=l[i]*r[n-i+n];
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2019-08-08 00:35  双子最可爱啦  阅读(254)  评论(0编辑  收藏  举报