1. 程式人生 > 實用技巧 >BZOJ-1303 [CQOI2009]中位數圖(字首和+計數)

BZOJ-1303 [CQOI2009]中位數圖(字首和+計數)

題目描述

  給出 \(1,2,\cdots,n(n\leq 10^5)\) 的一個排列,統計該排列有多少個長度為奇數的連續子序列的中位數是 \(b\)。中位數是指把所有元素從小到大排列後,位於中間的數。

分析

  讀入的時候把大於 \(b\) 的數賦值為 \(1\),小於 \(b\) 的數賦值為 \(-1\)\(b\) 的下標設為 \(pos\)。設 \(l[i]\)\(pos\) 左邊的字尾和為 \(i\) 的字尾數目,\(r[i]\)\(pos\) 右邊的字首和為 \(i\) 的字首數目。列舉 \(-10^5\leq x\leq 10^5\)\(l[x]\) 可以與 \(r[-x]\)

匹配,方案數為 \(l[x]\times r[-x]\)。答案即為 \(\displaystyle\sum_{i=-10^5}^{10^5}l[i]\times r[-i]\)

程式碼

#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
int a[N+10],l[4*N+10],r[4*N+10];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
int main()
{
    int n,b,pos;
    cin>>n>>b;
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        if(a[i]>b)
            a[i]=1;
        else if(a[i]==b)
            pos=i;
        else
            a[i]=-1;
    }
    l[N+0]=r[N+0]=1;
    int sum=0;
    for(int i=pos-1;i>=1;i--)
    {
        sum=sum+a[i];
        l[N+sum]++;
    }
    sum=0;
    for(int i=pos+1;i<=n;i++)
    {
        sum=sum+a[i];
        r[N+sum]++;
    }
    long long ans=0;
    for(int i=0;i<=N+100000;i++)
        ans=ans+l[i]*r[2*N-i];
    cout<<ans<<endl;
    return 0;
}