中位数计数
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 683 Accepted Submission(s): 277
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
显然要搞一种n^2的方法。枚举每一个下标为中位数的情况,显然就是需要在他前后
取某些连续的值使得比他大的数和比他小的数个数相等。这个很容易搞,把比他大
的数当做1,比他小的当做-1,自身当做0,前缀和以后相当于要在这个下标前后分别
找两个相等的前缀和。直接拿一个数组存一下就好了。
#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#include <set>
using namespace std;
#define maxn 8111
int a[maxn], num[maxn], sum[maxn];
int n;
int vis[maxn*2];
long long solve (int pos) {
long long ans = 0;
sum[0] = 0;
num[pos] = 0;
for (int i = 1; i <= n; i++) if (i != pos) {
if (a[i] > a[pos]) {
num[i] = 1;
}
else num[i] = -1;
}
for (int i = 1; i <= n; i++) {
sum[i] = sum[i-1]+num[i];
}
memset (vis, 0, sizeof vis);
for (int i = pos; i <= n; i++)
vis[sum[i]+8000]++;
for (int i = 0; i <= pos-1; i++) {
ans += vis[sum[i]+8000];
}
return ans;
}
int main () {
while (scanf ("%d", &n) == 1) {
for (int i = 1; i <= n; i++) {
scanf ("%d", &a[i]);
}
for (int i = 1; i <= n; i++) {
printf ("%I64d%c", solve (i), (i == n ? '\n' : ' '));
}
}
return 0;
}