[CQOI2009] 中位數 (前綴和)
阿新 • • 發佈:2018-11-07
輸入輸出 int its esp define strong tro 子序列 計算
在這\(n\)個數中有且只有一個
[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\)
這道題可以\(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] 中位數 (前綴和)