题目描述
给出1-n的一个排列,统计该排列有多少个长度为奇数的连续子序列的中位数是b。中位数是指把所有元素从小到大排列后,位于中间的数。
输入描述:
第一行为两个正整数n和b ,第二行为1~n 的排列。
输出描述:
输出一个整数,即中位数为b的连续子序列个数。
思路:
只在乎和b的相对大小,而不在乎具体多少,所以我们可以把大于b的值都定为1,小于b的值都为-1,这样的话,问题转化为,求有多少个区间的和为0,并且包含数字b的位置。
那么我们找出b的位置,然后从b的位置往前计算和,存入数组中,然后往右遍历计算和,看前面是不是已经存过了,存过了就加起来前面存的个数即可。
注意b单独一个数字也是一个区间,所以算完b前面的数字和后,满足的区间有1(b的位置本身)+f[0](前面的和为0的个数),然后把f[0]++,即先算出来b的位置作为区间右端点满足的个数,然后把b的位置加入区间左端点中。
注意和为负,所以开两个数组分别存正负的和
// 1 1 -1 0 -1 -1 1 #include<bits/stdc++.h> using namespace std; #define int long long int pos; int a[1<<17]; int z[1<<17],f[1<<17]; signed main(){ int n,b;cin>>n>>b; for(int i=1;i<=n;i++){ cin>>a[i]; if(a[i]>b) a[i]=1; else if(a[i]<b) a[i]=-1; else a[i]=0,pos=i; } int ans=0; for(int i=pos-1;i;i--){ ans+=a[i]; if(ans>0) z[ans]++; else f[-ans]++; } ans=0; int cnt=1+f[0]; f[0]++; for(int i=pos+1;i<=n;i++){ ans+=a[i]; if(ans>=0) cnt+=f[ans]; else cnt+=z[-ans]; } if(b>n) cnt=0; cout<<cnt; return 0; }