中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数。
现在有 n 个数,每个数都是独一无二的,求出每个数在多少个包含其的区间中是中位数。
现在有 n 个数,每个数都是独一无二的,求出每个数在多少个包含其的区间中是中位数。
第一行一个数 n(n≤8000)
第二行 n 个数, 0≤ 每个数 ≤109 ,
5 1 2 3 4 5
1 2 3 2 1
暴力+思维
感觉这个题目想法很独特
最暴力的方法应该是每个数每个区间去判断是否是中位数
但是对于算法这个东西来说,那当时是有一个比较简单的标记方法来实现是否最终结果
对于一个数字来说,他可以自身组成区间,也可以单独和前面组成区间,也可以单独与后面的数组成区间
1,自身组成区间,
2,与其前面(只有),或者只有它的后面的可以将它作为中位数的组成的区间(也就是她的前面的大于它的数等于他的前面小于他的数)
3,既有前面的数,又有后面的数
如何标记实现:
对于1,来说:sum+1即可;
对于2,来说:对每个数字,单独遍历其前和其后的数字,如果大于这个数字+1,小于这个数字减一(或者两个数字标记+1.-1的数量)如若结果等于0,那么sum++;前后分别遍 历,记得重置0
对于3,来说:一个book数组标记前边从后往前遍历的有大于这个数的可以有几个小于的可以有几个,看看能否凑在一起,可以则加起来!!!!
(不大好像,仔细体会)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int maxx=8010;
int main()
{
int n;
int a[maxx];
int cnt[2*maxx];
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
memset(cnt,0,sizeof(cnt));
int x=0; cnt[n]++;
for(int j=1;i-j>0;j++)
{
if(a[i-j]>a[i])
{
x++;
}
else
{
x--;
}
cnt[n+x]++;
}
int sum=cnt[n];
x=0;
for(int j=1;i+j<=n;j++)
{
if(a[i+j]>a[i])
{
x++;
}
else
{
x--;
}
sum+=cnt[n-x];
}
if(i!=1)
{
printf(" ");
}
printf("%d",sum);
}
printf("\n");
}
return 0;
}