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;
}

浙公网安备 33010602011771号