HDU 5701 中位數計數 (思維題)
阿新 • • 發佈:2019-01-12
題目連結
中位數定義為所有值從小到大排序後排在正中間的那個數,如果值有偶數個,通常取最中間的兩個數值的平均數作為中位數。
現在有nn個數,每個數都是獨一無二的,求出每個數在多少個包含其的區間中是中位數。
Input
多組測試資料
第一行一個數n(n≤8000)n(n≤8000)
第二行nn個數,0≤0≤每個數≤109≤109,
Output
NN個數,依次表示第ii個數在多少包含其的區間中是中位數。
Sample Input
5
1 2 3 4 5
Sample Output
1 2 3 2 1
PS:這個題是一個很不錯的思維題,首先我們宣告一個ans陣列儲存答案,一個數組num儲存左邊右邊比當前數打或者小的數的個數,已a[i]來討論,有三種情況。
1.討論它左邊的區間,從(i-1)向左遍歷,注意一定是這樣遍歷,不然不能夠保證連續區間,然後宣告一個num記錄比它大或者比他小的數,遇到比它大的數,num++,反之num--,如果num==0,說明在他的左區間比他大的數和比它小的數個數一樣,它直接能夠是中位數,ans[i]++,因為num可以是負數,所以在陣列記錄的時候需要提前加個大數,直接num[maxn+sum]++。
2.討論它右邊的區間,從(i+1)向右遍歷。其他情況和向左遍歷的情況一樣。
3.同時討論a[i]的左右區間。直接ans[i]+=num[maxn-sum];說一下為什麼這樣可以。若是左邊有兩個比它大的,num記錄的num[maxn+2]等於1,需要在右邊右邊找兩個比它小的數num==-1。所以直接ans[i]+=num[maxn-(-2)]等於ans[i]+=num[maxn+2]。
#include <iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #include<stack> #include<string> const int maxn=8e3+10; const int mod=10007; const int inf=1e8; #define me(a,b) memset(a,b,sizeof(a)) #define lowbit(x) x&(-x) typedef long long ll; using namespace std; int main() { int n,a[maxn],ans[maxn]; while(scanf("%d",&n)!=EOF) { for(int i=1;i<=n;i++) { scanf("%d",&a[i]); ans[i]=1; } for(int i=1;i<=n;i++) { int num[maxn<<2],sum=0; me(num,0); for(int j=i-1;j>=1;j--) { if(a[j]>a[i]) sum++; else sum--; if(sum==0)//他的左區間比他大的數和比它小的數個數一樣,它直接能夠是中位數 ans[i]++; num[maxn+sum]++; } sum=0; for(int j=i+1;j<=n;j++) { if(a[j]>a[i]) sum++; else sum--; if(sum==0)//他的左區間比他大的數和比它小的數個數一樣,它直接能夠是中位數 ans[i]++; ans[i]+=num[maxn-sum];//加上左邊數量對應的數目 } } for(int i=1;i<n;i++) printf("%d ",ans[i]); printf("%d\n",ans[n]); } return 0; }