中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数。
现在有n个数,每个数都是独一无二的,求出每个数在多少个包含其的区间中是中位数。
第一行一个数n(n<=8000) 第二行n个数,0<=每个数<=10^9
N个数,依次表示第i个数在多少包含其的区间中是中位数。
5 1 2 3 4 5
1 2 3 2 1
对于第i个,我们有四种可能
1: 单独这一个
2: j 到 i
3: i 到 j
4: j1 到 i 到 j2
我们需要挨个求。我们现在求第i个
cnt=1 //第一个肯定满足
我们这里一个tongji,记录1到i-1中比当前值大小的情况,对于每一个位置j,如果当前值大于i,则+1,否则-1.
如果到第j位,tongji==0,说明比i大的和比i小的一样多,那么当前j到i,i肯定就是中位数。 这样求出说有j到i的情况
同时我们统计一下i前面所有的可能性。也就是j到i距离为1的有几个,距离为2的有几个。 方便后面查询 j1 到 i 到 j2。
之后我们在遍历i+1到n ,相同的办法先找出所有的i到j的情况。
同时对于第j个,假设当前第j个的tongji值为1,这是在i到j找到的, 如果 前面1到i-1之间也有tongji为1的,那么一连接,不就是第四种情况嘛。 可能有人疑问,后面1和前面1,连接后不是0啊.不能保证i是中位数。我们这段遍历时,我们反着来即可,1-i我们是小的+1,大的-1.我们这里小的-1,大的+1.这样来遍历不就可以了嘛。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<iostream>
using namespace std;
int a[10000];
int tongji[10000];
int shuchu[10000];
int xiangtong[20000];
int n,cnt,dangqian;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++) //对于第i个
{
cnt=1;//自身就是一个
dangqian=a[i];//当前值
memset(tongji,0,sizeof(tongji));
memset(xiangtong,0,sizeof(xiangtong));
for(int j=i-1;j>=1;j--)
{
if(a[j]<dangqian)//如果第j个小于当前值
{
tongji[j]=tongji[j+1]+1; //+!
}
else
{
tongji[j]=tongji[j+1]-1; //-1
}
xiangtong[tongji[j]+n]++; //统计相同情况的总个数
if(tongji[j]==0)//如果当前为0,说明没大也没小,或者大的等于小的,抵消了。那么j到i就是中位数
{
cnt++;
}
}
for(int j=i+1;j<=n;j++)
{
if(a[j]<=dangqian)
{
tongji[j]=tongji[j-1]-1;
}
else
{
tongji[j]=tongji[j-1]+1;
}
if(tongji[j]==0)
{
cnt++;
}
if(xiangtong[tongji[j]+n]>0)
{
cnt+=xiangtong[tongji[j]+n];
}
}
shuchu[i]=cnt;
}
for(int i=1;i<n;i++)
cout<<shuchu[i]<<" ";
cout<<shuchu[n]<<endl;
}