基准时间限制: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; }