Ps:数据范围:

一道比较套路的题了

因为对于一个数a[i],我们其实只需要知道它与b的大小关系就行了,并不需要知道其准确的值,所以,我们可以将每个点变为它对它所在的所有区间的中,这个数添加进区间后,会对b到中位数的位置的变化的贡献是多少:

如果a[i]>b,那么,它会使得b的位置向左移一位,所以,贡献就是-1

如果a[i]=b,没有影响,贡献为0

如果a[i]<b,那么,他会使得b的位置向右移动一位,所以贡献就是1

当然,你也可以这么理解:

因为一个点是中位数(区间长度为奇数且无重复)当前仅当小于这个数的数字的个数==大于这个数的数字的个数。

那么,我们只需要知道,小于b的数的个数-大于b的数的个数为多少就行了,如果为0,就是合法的一个答案。那么,每个点对这个值的贡献就是上面说的那个

现在,我们来做下题。

我们将每个点转化后,题目就等价于求,有多少个区间的区间和为0,且包含b

那么,我们就可以按套路,将一个包含b的区间分为左右两部分,如果左边区间的小于b的数的个数-大于b的数的个数等于右边区间的小于b的数的个数-大于b的数的个数的相反数,那么这个就是个合法答案。

所以,我们可以所有左边/右边区间的小于b的数的个数-大于b的数的个数的值为x的区间的个数。设为num[x]

然后,我们再枚举右边/左边区间,求出当前区间的小于b的数的个数-大于b的数的个数的值S,那么,可以和这个区间构成合法区间的右边区间的个数就是num[-S]了

至于下标有负数的问题,可以一开始加个基础值,或者直接用map

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
int a[N];
map<int,int>s;
int main(){
    int n,b,now;
    scanf("%d%d",&n,&b);
    long long ans=0;
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
        if(a[i]==b)now=i;
    }
    for(int i=1;i<=n;++i){
        if(a[i]<b)a[i]=1;
        else if(a[i]==b)a[i]=0;
        else a[i]=-1;
    }
    int sum=0,lon;
    for(int i=now;i<=n;++i){//枚举右端点
        sum+=a[i];++s[sum];
    }
    sum=0;
    for(int i=now;i;--i){//枚举左端点
        sum+=a[i];ans+=s[-sum];
    }
    printf("%lld",ans);
    return 0;
}