中位数计数
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2065 Accepted Submission(s): 717
题目链接:点击打开链接
Problem Description
中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数。
现在有 n 个数,每个数都是独一无二的,求出每个数在多少个包含其的区间中是中位数。
现在有 n 个数,每个数都是独一无二的,求出每个数在多少个包含其的区间中是中位数。
Input
多组测试数据
第一行一个数 n(n≤8000)
第二行 n 个数, 0≤ 每个数 ≤109 ,
第一行一个数 n(n≤8000)
第二行 n 个数, 0≤ 每个数 ≤109 ,
Output
N
个数,依次表示第
i
个数在多少包含其的区间中是中位数。
Sample Input
5
1 2 3 4 5
Sample Output
1 2 3 2 1
5
1 2 3 4 5
Sample Output
1 2 3 2 1
题意:
肯定有人对题意理解的不对,就像第一次看题的我,本题是给你一组数(注意这组数不是排好序的,是无序的,题上的测试数据只是一个特例),然后让你对这组数进行遍历,找出每个数所在的区间里它是中位数的情况,比如测试数据中的4,它对应的值是2,包含4的区间有(1 2 3 4)(2 3 4)(3 4)(4)(4 5)(1 2 3 4 5)(2 3 4 5)(3 4 5) ,但是他在区间(4)和区间(3 4 5)中是中位数,还有一点就是,本题因为没有重复的数字,每个数字都是独一无二的,所以不存在以该数为中位数的偶数个数字的区间(你想啊,因为偶数个数的中位数是两个数的加和除以2,但是没有两个一样的数字,所以中位数肯定不为该数)。
分析:
我们可以定义一个神秘的数组,之所以说它神秘,是它的巧妙之处可以帮我们解决所有的问题,这个数组只要理解了,本题就过了,说说思想吧,就是先扫一下 i 右边的数,求出比它大的数的个数减去比它小的个数的差值,然后再
扫一下 i 左边的数,求出比它小的数的个数减去比它大的个数的差值,如果两个差值相等的话,是不是该数就是这个区间里的中位数了,恩恩,就这样,但代码中你必须要理解好 h 数组的含义。、
#include <stdio.h>
#include <string.h>
const int INF = 8005;
int s[INF],h[INF*2];///h数组一定要定义两倍大,以防数组下标越界
int main()
{
int n,ans,num;
while(scanf("%d",&n)!= EOF)
{
for(int i=0;i<n;i++)
scanf("%d",&s[i]);
for(int i=0;i<n;i++)
{
num=0,ans=0;///从左扫从右扫之前都要将num置0,它存的是比该数大和比该数小的数
memset(h,0,sizeof(h));///初始化将该数组刷为0
h[INF]++;///这个表示自身一个数的情况,也是可行的
for(int j=i+1;j<n;j++)///从右边扫
{
if(s[j]>s[i])///如果大于该数,num++
num++;
else///否则num--,这样就可以求出差值了
num--;
h[INF+num]++;///这个带点自己理解,动手模拟
}
num=0;
ans+=h[INF];///让区间里比它大的数和比它小的数相等的时候的情况累加
for(int j=i-1;j>=0;j--)///扫左边
{
if(s[j]<s[i])///如果小于该数,num++
num++;
else///否则num--
num--;
ans+=h[INF+num];
/**如果该数组里再扫右边得时候已经统计过,那么再遇见,就代表该区间可以
让该数成为中位数**/
}
if(i<n-1)///这个是控制空格的情况
printf("%d ",ans);
else
printf("%d\n",ans);
}
}
return 0;
}