P1168 中位数

Posted returng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1168 中位数相关的知识,希望对你有一定的参考价值。

题目链接

题意:

? 对于给定序列,求出前奇数个元素的中位数。

思路:

? 既然要求中位数,根据题目一看,有点类似与滑动窗口那道题,但想了想,不一样。暴力维护队列,O($n^2$)的时间复杂度面对十万肯定会爆,再试试之前学过的STL模板的优先队列和set是否可以,发现两者对于中位数的查找似乎显得力不从心,想到的只剩下二分了。

为什么考虑二分?

? 我们学过插入排序来维护序列,当一个元素加入序列时,将其插入它的理想位置,就像平时斗地主搓麻将理牌一样,可以有效的动态维护有序序列,二分优化后的时间复杂度为O($nlog_2(n)$)能够满足n=100000的要求。

大致流程:

  1. 对于当前元素,二分找到它的插入位置;
  2. 将其插入序列;
  3. 如果是第奇数个,输出序列中间的数;

实现中的小技巧:

? 我们需要一个既可以高效率实现插入又可以高效率访问中间元素的容器来存储序列,这种既满足链表,又满足数组的特征的容器是什么?vector!(学前误认一无是处,学后方知相见恨晚)

100分代码:

#include <bits/stdc++.h>
using namespace std;
int n;
vector<int> a;
inline int place(int l,int r,int v){
	if(l>r)return l;
	if(l==r){
		return l;
	}
	if(a[l]==v)return l;
	int mid=(l+r)/2;
	if(v<a[mid]){
		return place(l,mid-1,v);
	}
	if(v==a[mid]){
		return mid;
	}
	if(v>a[mid]){
		return place(mid+1,r,v);
	}
}
int main() {
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	scanf("%d",&n);
	a.push_back(-1);
	for(register int i=1;i<=n;i++){
		int x;
		scanf("%d",&x);
		int ne=place(0,i-1,x);
		while(x<=a[ne-1]&&ne>=1)ne--;//a[ne]<x
		while(a[ne]<x&&ne<a.size())ne++;
		//cout<<ne<<endl;
		vector<int>::iterator it=a.begin()+ne;//a[*it]<=x<a[*it+1]
		//while(a[*it]>x)it++;
		a.insert(it,x);
		//for(int j=0;j<a.size();j++)cout<<a[j]<<‘ ‘;
		//cout<<endl;
		if(i%2==1){
			printf("%d
",a[(i+1)/2]);
		}
	}
	return 0;
}

? 注:程序本身是考场上胡乱打出的非完全体,所以bug比较多,代码中可以看出加了许多“补丁”。还有,注意不要用cin,cout,会超时等等,还有很多小细节,可以自行去挖掘。

另外几种可行的思路:lower_bound(),堆,平衡树。

以上是关于P1168 中位数的主要内容,如果未能解决你的问题,请参考以下文章

P1168 中位数

洛谷P1168 中位数 堆

[luogu]P1168 中位数[堆]

洛谷—— P1168 中位数

P1168 中位数

[洛谷P1168]中位数