zoukankan      html  css  js  c++  java
  • uoj280 【UTR #2】题目难度提升 堆维护中位数+set

    题目传送门

    http://uoj.ac/problem/280

    题解

    这道题很妙啊。

    这种题目如果给予选手足够的时间,每一个选手应该都能做出来。

    大概就是核心思路看上去很简单,但是想要推出来并不简单。


    首先考虑如果没有重复的元素应该怎么做。

    第一个数应该就是最小值。

    在没有重复元素的时候,新加入一个数想要保证中位数不下降就必须要满足这个数大于等于前面的中位数。

    所以选择加入某个数的时候的判断条件就是加入这个数以后,剩下的最小的数比中位数大。

    具体实现的时候,可以先取出这个最小的数。如果前面的元素数量是奇数,那么加入它以后中位数是中间两个数的平均值,所以需要讨论这个最小的数和之前中位数的关系。如果大于之前的中位数,那么我们可以直接选择剩下的数里面最大的——因为不管加进去谁,以后的中位数都没有这个最小的数大,所以可以直接放心地加入最大的;否则,假设之前的中位数为 (pp),新加入的数为 (x),之前取出的最小数为 (v),那么之后的中位数 (frac{pp + x}2)(geq v)。所以 (x) 可以取 (leq 2v - pp) 的最大的数。

    如果之前元素数量是偶数,那么加入以后它的中位数就是一个固定的数,不随加入了哪个数改变。如果最小的数大于等于这个数,那么直接加入最大的都不会有影响;否则加入最小的数。

    维护中位数可以使用堆。


    考虑有了重复的元素的做法。

    如果重复的元素在整个集合的 (mid) 的后面,那么不会影响。

    如果经过 (mid) 那么可以直接以经过 (mid) 的这个重复元素的值的最后一位为开始,先输出这个数,然后输出小于等于这个数的最大数,然后大于这个数的最大的数,并删除;重复这个过程,知道后面被删光了。然后把剩下的从大到小输出就可以了。正确性很显然。

    如果不经过呢,那么我们找到小于 (mid) 的最大的重复元素,先把小于这个重复元素的全部按照一个小于等于这个数的最大数,一个大于这个数的最大的数的方案输出完。下面应该只剩下大于这个重复元素的了,可以按照上面没有重复元素的做法。


    时间复杂度 (O(nlog n))

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 1e5 + 7;
    
    int n, pp, sz;
    int a[N];
    std::multiset<int> s;
    std::priority_queue<int, std::vector<int>, std::greater<int> > q;
    
    inline void qadd(int x) {
    	++sz, q.push(x);
    	while (q.size() * 2 > sz) pp = q.top(), q.pop();
    }
    
    inline void work() {
    	std::sort(a + 1, a + n + 1);
    	if (a[(1 + n) / 2] == a[(1 + n) / 2 + 1]) {
    		int p = (1 + n) / 2, p1, p2 = n;
    		while (p < n && a[p] == a[p + 1]) ++p;
    		p1 = p;
    		printf("%d ", a[p1--]);
    //		dbg("******** %d %d
    ", p1, p2);
    		while (p1 && p2 > p) printf("%d %d ", a[p1--], a[p2--]);//, dbg("*** %d %d, -> %d
    ", p1, p2, (1 + n) / 2);
    		while (p1) printf("%d ", a[p1--]);
    		return;
    	}
    //	dbg("****************
    ");
    	int p, p1, p2;
    	for (p = (1 + n) / 2; p > 1 && a[p] != a[p - 1]; --p) ;
    	if (p > 1 && a[p] == a[p - 1]) {
    		p1 = p, p2 = n;
    		printf("%d ", a[p1--]);
    		while (p1 && p2 > p) printf("%d %d ", a[p1--], a[p2--]);
    		for (int i = 1; i <= p1; ++i) s.insert(a[i]);
    		for (int i = p1 + 1; i <= p; ++i) qadd(a[i]);
    		for (int i = p + 1; i <= p2; ++i) s.insert(a[i]);
    		for (int i = p2 + 1; i <= n; ++i) qadd(a[i]);
    	} else {
    		qadd(a[1]);
    		printf("%d ", a[1]);
    		for (int i = 2; i <= n; ++i) s.insert(a[i]);
    	}
    //	dbg("****************
    ");
    	while (!s.empty()) {
    		int min = *s.begin();
    		std::multiset<int>::iterator it;
    		if (!(sz & 1)) {
    			if (min < q.top()) it = s.begin();
    			else it = s.end(), --it;
    		} else {
    			if (q.empty() || min * 2 < pp + q.top()) it = s.upper_bound(min * 2 - pp), --it;
    			else it = s.end(), --it;
    		}
    		qadd(*it), printf("%d ", *it), s.erase(it);
    	}
    }
    
    inline void init() {
    	read(n);
    	for (int i = 1; i <= n; ++i) read(a[i]);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    Android Developers:在命令行构建和运行
    pjsip视频通信开发(上层应用)之数字键盘的制作
    Oracle使用goldengate分别向Oracle和mysql双路的单向复制
    js数组的操作
    goldengate的HANDLECOLLISIONS参数
    SQL注入之导出WebShell
    GNURADIO简单运用
    利用Teensy进行EM410x卡模拟以及暴力破解EM410X类门禁系统可行性猜想
    Discuz! 6.x/7.x 版本 前台任意代码执行漏洞
    python之web路径扫描工具
  • 原文地址:https://www.cnblogs.com/hankeke/p/uoj280.html
Copyright © 2011-2022 走看看