基准时间限制: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)。
定义一个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;
}