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