HDU5701(技巧暴力)

来源:互联网 发布:嵌入式软件开发技术 编辑:程序博客网 时间:2024/06/06 16:43

一开始看这道题目的时候让我想起来以前看过的一道面试题,结果写上去超时。。

接下来入正题,那道面试题我在最后分享一下。

数据只有8000,n^2能过,只能暴力枚举每个数了。

首先把大于arr[i]的数改成1小于改成-1,等于改成0(其实只有自己等于自己)

一般连续区间的题目大概率都用到线段树和前缀和,这里用到了前缀和。

从i开始到n把前缀和都记录下来,这样如果前缀和为0就表示该数为中位数。(右扫描)

接下来在计算i到1的(左扫描),计算过程中如果左边的前缀于右边的前缀和相加为0,

那么要ans++,但这样比较费时,那么用Hash数组记录下右边前缀和,下标表示前缀和,值表示该等于前缀和的前缀有多少个,

这样ans+=Hash[],就大大节约了时间,但是前缀和可能为负数,所以加一个偏移量med=8000;

代码如下:

                #include<iostream>                #include<cstring>using namespace std;int arr[8005];//数组 int sym[8005];//0 -1 1 的标志 int sum[8005];//前缀和 int Hash[8005*2];//以前缀和为下标记录等于前缀和的前缀个数 const int med=8000;int main(){        int n;while(cin>>n){for(int i=1;i<=n;i++){scanf("%d",&arr[i]); }for(int i=1;i<=n;i++){memset(Hash,0,sizeof(Hash));for(int j=1;j<=n;j++){if(arr[i]>arr[j])sym[j]=-1;else if(arr[i]<arr[j])    sym[j]=1;else sym[j]=0;}sum[i]=0;Hash[med+sum[i]]++;for(int j=i+1;j<=n;j++)//右扫描 {sum[j]=sum[j-1]+sym[j];Hash[med+sum[j]]++;}int ans=0;ans+=Hash[med+0];    for(int j=i-1;j>=1;j--)//左扫描更新答案 {sum[j]=sum[j+1]+sym[j];ans+=Hash[med-sum[j]];}if(i!=n) printf("%d ",ans);else  printf("%d\n",ans);}}    } 

分享一下我见的那道面试题:

给你一个随时增加元素的数组,要求更新他的中位数。

当第一个元素来的时候中位数即为该数,

这个时候维护一个大顶堆和一个下顶堆

大顶堆放入比中位数小的元素,小顶堆放入比中位数大的元素。

当左右堆的大小差值超过1时,便调整左右堆,中位数加入元素更少的一个堆

然后中位数等于另一个堆的堆顶元素,这样便实现了动态调整。

维护的时间复杂度是 lon n。



原创粉丝点击