链接:https://ac.nowcoder.com/acm/contest/20960/1011 来源:牛客网
思路:一个奇数长度的序列,比它中位数大和比他中位数小的数个数是相等的。所以要让题目转化为找连续子序列,这个子序列比某个数大的个数和比某个数小的个数相等。这是两类情况,所以考虑用1和-1来标记。逐个读入输入的数,比要找的中位数大的在数组中记为1,小的记为-1,找到这个数记为0,同时把这个数的位置记下来,方便以后以这个数为中心找子串。我一开始想着以这个数为中心向左右扩散循环,判断区间和是否为0,这是显然不对的,因为找的子序列中只要包括这个数就行了。所以应该记录下左右各自区间的前缀和,又由于这个前缀和不一定连续,所以考虑用map存着,键代表某个前缀和(左区间的),值代表它的出现次数。用res记录下结果(由于排列中包含这个要找的数,这个数本身就符合题目要求,所以res初始值定为1)。sum记录着前缀和,从这个数左边开始(如果左右两边都记录一边就复杂了)前缀和,如果找到一个和为0的区间,结果就加1。然后别忘了把sum重新记为0,开始记录右边区间的前缀和,想一想,如果找到遇到了前缀和0,还要再写一遍if语句吗,可以写但复杂了,但这时可以把要找的数所在的位置也看在左区间里面(那么就要让键为0的值加一)。然后,如果前缀和为左边某个前缀和的相反数,那么左边那个前缀和出现多少次就找到了多少个子串。右边重复出现的前缀和也不用再记录次数了,让结果每次加对应的左边前缀和的相反数出现的次数就好。
代码:
```#include <bits/stdc++.h>
using namespace std;
int main()
{ map<int,int> m;
int num[100010];
int n,b,t,pos;scanf("%d%d",&n,&b);
for(int i=1;i<=n;i++)
{
scanf("%d",&t);
if(t>b){num[i]=1;}
else if(t<b){num[i]=-1;}
else{num[i]=0;pos=i;}
}
int sum=0;int res=1;
m[0]++;
for(int j=pos-1;j>=1;j--)
{
sum+=num[j];
if(sum==0){res++;}
m[sum]++;
}
sum=0;
for(int k=pos+1;k<=n;k++)
{
sum+=num[k];
res+=m[-sum];
}
cout<<res;
return 0;
}