HDU 5701 中位数计数 (思维题)

题目链接

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("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cmmdc/p/7904419.html