[CQOI2009] 中位數
阿新 • • 發佈:2018-11-03
不錯的思維題
傳送門:$>here<$
題意:給出一個N的排列,求出其中有多少個連續子段的中位數是b
資料範圍:$N \leq 100000$
$Solution$
先考慮中位數的意義:一個序列中,大於它的與小於它的一樣多。而由於中位數已經確定,所以最終的序列一定包含它所在的那個位置。
設$$c[i]=\begin{cases}0 & \text{} a[i]==b \\ 1 & \text{} a[i]>b \\ -1 & \text{} a[i]<b \end{cases}$$
於是如果我們統計一個$sum[i]$表示$c[i]$的字首和,在開一個桶表示左側右側對應的個數。就可以得到答案
$$ans = \sum\limits_{i=-N}^{+N}bl[i]*br[-i]$$
注意下標不能為負數
反思
對於無論是平均數還是中位數,對於計算機來說都不好處理。此時最好的辦法就是還原為最簡單的求和問題
$my \ code$
/*By DennyQi 2018*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; constint MAXN = 100010; const int INF = 1061109567; const int ad = 1e5; inline int Max(const int a, const int b){ return (a > b) ? a : b; } inline int Min(const int a, const int b){ return (a < b) ? a : b; } inline int read(){ int x = 0; int w = 1; register char c = getchar(); for(; c ^ '-' && (c < '0' || c > '9'); c = getchar()); if(c == '-') w = -1, c = getchar(); for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w; } int N,B,pos,Ans; int a[MAXN],c[MAXN],sum[MAXN],bl[MAXN*2],br[MAXN*2]; int main(){ N = read(), B = read(); for(int i = 1; i <= N; ++i){ a[i] = read(); if(a[i] < B) c[i] = -1; if(a[i] > B) c[i] = 1; if(a[i] == B) pos = i; sum[i] = sum[i-1] + c[i]; } for(int i = 0; i < pos; ++i){ bl[sum[pos-1]-sum[i]+ad]++; } for(int i = pos; i <= N; ++i){ br[sum[i]-sum[pos]+ad]++; } for(int i = -N; i <= N; ++i){ Ans += bl[i+ad] * br[-i+ad]; } printf("%d", Ans); return 0; }