• 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(),堆,平衡树。

  • 相关阅读:
    openmp
    opencv 读写矩阵
    string to const char*
    c++ string to number
    HDU 1520 Anniversary Party
    ZOJ 1003 Crashing Balloon
    HDU 4171 Paper Route
    ZOJ 2067 White Rectangles
    TOJ 1690 Cow Sorting (置换群)
    TOJ 2814 Light Bulb
  • 原文地址:https://www.cnblogs.com/returnG/p/13178978.html
Copyright © 2020-2023  润新知