junior19

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
 收藏
 关注

中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数。

现在有n个数,每个数都是独一无二的,求出每个数在多少个包含其的区间中是中位数。


Input
第一行一个数n(n<=8000)
第二行n个数,0<=每个数<=10^9
Output
N个数,依次表示第i个数在多少包含其的区间中是中位数。
Input示例
5
1 2 3 4 5
Output示例
1 2 3 2 1
Joe (题目提供者)
C++的运行时限为:1000 ms ,空间限制为:131072 KB 示例及语言说明请按这里
思路:
Joe (题目提供者)
考虑如何计算一个数的答案:
定义一个b数组,把所有大于自己的值定义为1,小于自己的值定义为-1,等于自己的定义为0。
如果包含这个数的区间这个数是中位数,则定义后的总和为0。
考虑前缀和,那么问题就变成了在这个数两边有多少对相等的数。
可以先把左边的数统计一下,右边的数就可以O(1)查询,时间复杂度O(n)
总时间复杂度O(N^2)。

# include <iostream>
# include <cstdio>
# include <cstring>
# include <vector>
# define MAXN 8000

using namespace std;
int a[MAXN+1], sum[MAXN+1], num[MAXN<<1|1], res[MAXN+1];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1; i<=n; ++i)
            scanf("%d",&a[i]);
        for(int i=1; i<=n; ++i)
        {
            sum[0] = 0;
            memset(num, 0, sizeof(num));
            int ans = 0;
            ++num[MAXN];
            for(int j=1; j<=n; ++j)
            {
                if(a[j]<a[i]) sum[j] = sum[j-1]-1;
                else if(a[j]==a[i]) sum[j] = sum[j-1];
                else sum[j] = sum[j-1]+1;
                if(j < i) ++num[sum[j]+MAXN];
                else ans += num[sum[j]+MAXN];
            }
            res[i] = ans;
        }

        for(int i=1; i<n; ++i)
            printf("%d ",res[i]);
        printf("%d\n",res[n]);
    }
    return 0;
}


posted on 2017-03-15 23:58  junior19  阅读(158)  评论(0编辑  收藏  举报