[CQOI2009] 中位數 (前綴和)

[CQOI2009] 中位數

題目描述

給出1~n的一個排列,統計該排列有多少個長度爲奇數的連續子序列的中位數是b。中位數是指把全部元素從小到大排列後,位於中間的數。c++

輸入輸出格式

輸入格式:數組

第一行爲兩個正整數n和b,第二行爲1~n的排列。spa

【數據規模】code

對於30%的數據中,知足n≤100;get

對於60%的數據中,知足n≤1000;it

對於100%的數據中,知足n≤100000,1≤b≤n。io

輸出格式:class

輸出一個整數,即中位數爲b的連續子序列個數。map

輸入輸出樣例

輸入樣例#1:方法

7 4
5 7 2 4 3 1 6

輸出樣例#1:

4

Solution

首先題目有一個隱含的性質,由於是排列,而又保證\(b\)出現過,因此\(b\)在這\(n\)個數中有且只有一個

這道題能夠\(O(n^2)\)經過統計前綴和拿到60分,咱們只關心相對大小,因此能夠把大於\(b\)的設成1,小於\(b\)的設成-1

由於是中位數,因此先後的數字個數一定相等,在咱們設了1/-1以後,又多了一個條件,即左邊的數字的和+右邊數字的和=0(想想就知道了)

那麼咱們就能夠先統計一邊的前綴和的個數,再在另外一邊一邊計算前綴和一邊統計答案,由於可能會有負數,因此有兩種方法,一種是把數組平移,一種是開\(map\)

具體結合代碼(畫一下)就懂了

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
#define il extern inline
#define rg register
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define lol long long
using namespace std;

const lol N=1e5+10;

lol read() {
    lol ans=0, f=1; char i=getchar();
    while (i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while (i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48), i=getchar();
    return ans*f;
}

int n,m,sum,ans,pos,a[N];
map<int,int>cnt;

int main()
{
    in(n), in(m);
    for (rg int i=1;i<=n;i++) {
        in(a[i]);
        if(a[i]>m) a[i]=1;
        else if(a[i]==m) a[i]=0, pos=i;
        else a[i]=-1;
    }
    for (int i=pos;i<=n;i++)
        sum+=a[i], cnt[sum]++;
    sum=0;
    for (int i=pos;i>=1;i--)
        sum+=a[i], ans+=cnt[-sum];
    cout<<ans<<endl;
}
相關文章
相關標籤/搜索