1. 程式人生 > >[CQOI2009] 中位數 (前綴和)

[CQOI2009] 中位數 (前綴和)

輸入輸出 int its esp define strong tro 子序列 計算

[CQOI2009] 中位數

題目描述

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

輸入輸出格式

輸入格式:

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

【數據規模】

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

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

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

輸出格式:

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

輸入輸出樣例

輸入樣例#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;
}

[CQOI2009] 中位數 (前綴和)