链接
http://codeforces.com/contest/1005/problem/E2
题解
思路清奇
令
表示中位数大于等于
且包含
的区间个数,
表示这个数列里最小的比
大的数,若
不存在,答案为
,若
存在,答案为
先找到第一个
,指针
指向这个位置,凡是左端点在这个
左侧,右端点在这个
右侧(inclusive)的区间都是“包含
的区间”。
计算
:
大于等于
的数我设为
,小于
的数我设为
,一个区间的和如果大于等于
,就肯定要被计入答案。前缀和一下,
,
,我开一个值域
,把
右侧(inclusive)的
在其值对应的位置
,然后扫描左侧,每次把
计入答案,其中
是整个
的和。
然后移动
指向下一个
,把两个
之间的这一段
从
里剔除,再统计这一段区域的答案
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
#define maxn 200010
#define mst(x) memset(x,0,sizeof(x))
#define lowbit(x) (x&-x)
using namespace std;
ll n, m, a[maxn], b[maxn], s[maxn], bit[maxn<<1], c[maxn<<1];
ll bitsum(ll pos)
{
ll ans=0;
for(;pos;pos-=lowbit(pos))ans+=bit[pos];
return ans;
}
void bitadd(ll pos, ll x){if(pos>0)for(;pos<=(n<<1);pos+=lowbit(pos))bit[pos]+=x;}
ll find_next(ll x)
{
for(x++;x<=n;x++)if(a[x]==m)return x;
return -1;
}
ll work(ll x)
{
ll p, i, ans=0, to;
mst(bit), mst(b), mst(s);
for(p=1;p<=n;p++)if(a[p]==m)break;
if(p>n)return 0;
for(i=1;i<=n;i++)if(a[i]>=x)b[i]=1; else b[i]=-1;
for(i=1;i<=n;i++)s[i]=s[i-1]+b[i];
for(i=p;i<=n;i++)bitadd(s[i]+n,1);
for(i=0;i<p;i++)ans+=bitsum(n<<1)-bitsum(s[i]+n);
for(to=find_next(p);to^-1;to=find_next(to))
{
for(i=p;i<to;i++)bitadd(s[i]+n,-1);
for(i=p;i<to;i++)ans+=bitsum(n<<1)-bitsum(s[i]+n);
p=to;
}
return ans;
}
ll read(ll x=0)
{
char c;
for(c=getchar();c<48 or c>57;c=getchar());
for(;c>=48 and c<=57;c=getchar())x=(x<<1)+(x<<3)+c-48;
return x;
}
int main()
{
ll i, y=0x3f3f3f3f, ans;
n=read(), m=read();
for(i=1;i<=n;i++)
{
a[i]=read();
if(a[i]>m)y=min(y,a[i]);
}
ans=work(m);
if(y^0x3f3f3f3f)ans-=work(y);
printf("%I64d",ans);
return 0;
}