题目链接
中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数。
现在有nn个数,每个数都是独一无二的,求出每个数在多少个包含其的区间中是中位数。
Input
多组测试数据
第一行一个数n(n≤8000)n(n≤8000)
第二行nn个数,0≤0≤每个数≤109≤109,
Output
NN个数,依次表示第ii个数在多少包含其的区间中是中位数。
Sample Input
5
1 2 3 4 5
Sample Output
1 2 3 2 1
PS:这个题是一个很不错的思维题,首先我们声明一个ans数组保存答案,一个数组num保存左边右边比当前数打或者小的数的个数,已a[i]来讨论,有三种情况。
1.讨论它左边的区间,从(i-1)向左遍历,注意一定是这样遍历,不然不能够保证连续区间,然后声明一个num记录比它大或者比他小的数,遇到比它大的数,num++,反之num--,如果num==0,说明在他的左区间比他大的数和比它小的数个数一样,它直接能够是中位数,ans[i]++,因为num可以是负数,所以在数组记录的时候需要提前加个大数,直接num[maxn+sum]++。
2.讨论它右边的区间,从(i+1)向右遍历。其他情况和向左遍历的情况一样。
3.同时讨论a[i]的左右区间。直接ans[i]+=num[maxn-sum];说一下为什么这样可以。若是左边有两个比它大的,num记录的num[maxn+2]等于1,需要在右边右边找两个比它小的数num==-1。所以直接ans[i]+=num[maxn-(-2)]等于ans[i]+=num[maxn+2]。
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=8e3+10;
const int mod=10007;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
typedef long long ll;
using namespace std;
int main()
{
int n,a[maxn],ans[maxn];
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
ans[i]=1;
}
for(int i=1;i<=n;i++)
{
int num[maxn<<2],sum=0;
me(num,0);
for(int j=i-1;j>=1;j--)
{
if(a[j]>a[i])
sum++;
else
sum--;
if(sum==0)//他的左区间比他大的数和比它小的数个数一样,它直接能够是中位数
ans[i]++;
num[maxn+sum]++;
}
sum=0;
for(int j=i+1;j<=n;j++)
{
if(a[j]>a[i])
sum++;
else
sum--;
if(sum==0)//他的左区间比他大的数和比它小的数个数一样,它直接能够是中位数
ans[i]++;
ans[i]+=num[maxn-sum];//加上左边数量对应的数目
}
}
for(int i=1;i<n;i++)
printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
return 0;
}