题意:
在全排列中找长度为奇数的连续子序列,且中位数是b,问一共可以找到多少个连续子序列。
分析:
既然是全排列,我们就不需要考虑有多个b的情况了。
那么我们就可以把b的位置记录下来,然后往两边扩展。
设b的位置为pos。
lmin[i]表示[i,pos-1]中比b小的有多少个
lmax[i]表示[i,pos-1]中比b大的有多少个
rmin[j]表示[pos+1,j]中比b小的有多少个
rmax[j]表示[pos+1,j]中比b大的有多少个
那么在区间[i,j]中,满足条件的就是这三种情况
lmin[i]+rmin[j]==lmax[i]+rmax[j] (i<pos<j)
lmin[i]==lmax[i] (i<pos)
rmin[j]==rmax[j] (j>pos)
后两种情况我们在处理数组的时候就可以统计到。
但是第一种情况怎么办呢?
其实也很简单。
我们变一下形,lmin[i]-max[i]==-(rmin[j]-rmax[j])
显然我们可以先预处理出来他们的个数,然后直接乘起来(乘法原理)
看代码就完事了
#include <bits/stdc++.h>
#define sc(n) scanf("%d",&n)
#define pt(n) printf("%d\n",n)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define vi vector<int>
#define vl vector<long long>
#define pb push_back
using namespace std;
const int maxn = 1e5+7;
int a[maxn];
int lmin[maxn],lmax[maxn],rmin[maxn],rmax[maxn];
map<int,long long> t1,t2;
int n,b;
int main()
{
scanf("%d%d",&n,&b);
int pos = 0;
long long ans = 0;
rep(i,1,n)
{
sc(a[i]);
if(a[i]==b) pos = i;
}
for(int i=pos-1;i>=1;i--)
{
lmin[i] = lmin[i+1];
lmax[i] = lmax[i+1];
if(a[i]<b) lmin[i]++;
else lmax[i]++;
if(lmin[i]==lmax[i]) ans++;
}
for(int i=pos+1;i<=n;i++)
{
rmin[i] = rmin[i-1];
rmax[i] = rmax[i-1];
if(a[i]<b) rmin[i]++;
else rmax[i]++;
if(rmin[i]==rmax[i]) ans++;
}
for(int i=1;i<pos;i++)
{
t1[lmin[i]-lmax[i]]++;
}
for(int i=pos+1;i<=n;i++)
{
t2[rmin[i]-rmax[i]]++;
}
for(int i=-n;i<=n;i++)
{
ans += t1[i]*t2[-i];
}
printf("%lld\n",ans+1);
return 0;
}