Problem Description
中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数。
现在有n个数,每个数都是独一无二的,求出每个数在多少个包含其的区间中是中位数。
Input
多组测试数据
第一行一个数n(n≤8000)
第二行n个数,0≤每个数≤109,
Output
N个数,依次表示第i个数在多少包含其的区间中是中位数。
Sample Input
5
1 2 3 4 5
Sample Output
1 2 3 2 1
分析:
通过题目可得知,a[i]为中位数所在的区间一定是奇区间,
1、枚举每一个i,找出a[i],即以a[i]为中位数的区间个数
2、a[i]包括以下三种情况
①: i与其左边的数构成一个新数组,初始Count=0,如果左边的数比i大(小),那么Count+1,反之Count-1,每一次Count变成0,都意味着这个数左边的数字中大于i与小于i的个数相同,即此时i就是中位数,ans++
②: i与其右边的数构成一个新数组,初始Count=0,如果右边的数比i大(小),那么Count+1,反之Count-1,每一次Count变成0,都意味着这个数右边的数字中大于i与小于i的个数相同,即此时i就是中位数,ans++
③: 数组由i的左边和右边共同组成,用另一个数组cnt[]记录i往左找时各个Count的出现次数,在往右边找时,cnt[n+Count]就表示了左右两边比i大(小)和比i小(大)的数目之和相同,即此时i就是中位数,ans+=cnt[n+Count]
代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
int a[8009],cnt[16009];
int main()
{
int n,ans;
while(~scanf("%d",&n))
{
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
int Count;
for(int i=0; i<n; i++)
{
Count=0;//统计大于和小于的个数差
ans=0;//答案
memset(cnt,0,sizeof(cnt));//每次循环的时候都要进行刷新
for(int j=i-1; j>=0; j--)//找这个数字左边的
{
if(a[i]>a[j])
Count--;
else
Count++;
if(Count==0)//左边大于它本身和小于它本身的个数相等,这个数是左边这些数的中位数
ans++;
cnt[8000+Count]++;//标记左边比这个数大或小的数字的个数
}
Count=0;
for(int j=i+1; j<n; j++)
{
if(a[i]<a[j])
Count--;
else
Count++;
if(Count==0)//这个数是右边这些数的中位数
ans++;
ans+=cnt[8000+Count];//右边应该是比这个数字小或大的数字的个数
}
if(i==0)
printf("%d",ans+1);//最后加上一个本身是本身的中位数
else
printf(" %d",ans+1);
}
printf("\n");
}
return 0;
}