题目传送门

http://uoj.ac/problem/280

题解

这道题很妙啊。

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

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


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

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

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

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

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

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

维护中位数可以使用堆。


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

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

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

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


时间复杂度 \(O(n\log 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\n", p1, p2);
while (p1 && p2 > p) printf("%d %d ", a[p1--], a[p2--]);//, dbg("*** %d %d, -> %d\n", p1, p2, (1 + n) / 2);
while (p1) printf("%d ", a[p1--]);
return;
}
// dbg("****************\n");
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("****************\n");
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;
}

uoj280 【UTR #2】题目难度提升 堆维护中位数+set的更多相关文章

  1. 【uoj#280】[UTR #2]题目难度提升 对顶堆+STL-set

    题目描述 给出 $n$ 个数 $a_1,a_2,...,a_n$ ,将其排为序列 $\{p_i\}$ ,满足 $\{前\ i\ 个数的中位数\}$ 单调不降.求字典序最大的 $\{p_i\}$ . 其 ...

  2. 【UTR #2】[UOJ#278]题目排列顺序 [UOJ#279]题目交流通道 [UOJ#280]题目难度提升

    [UOJ#278][UTR #2]题目排列顺序 试题描述 “又要出题了.” 宇宙出题中心主任 —— 吉米多出题斯基,坐在办公桌前策划即将到来的 UOI. 这场比赛有 n 道题,吉米多出题斯基需要决定这 ...

  3. 洛谷 P3644 [APIO2015]八邻旁之桥(对顶堆维护中位数)

    题面传送门 题意: 一条河将大地分为 \(A,B\) 两个部分.两部分均可视为一根数轴. 有 \(n\) 名工人,第 \(i\) 名的家在 \(x_i\) 区域的 \(a_i\) 位置,公司在 \(y ...

  4. uoj#280. 【UTR #2】题目难度提升(构造)

    传送门 咱先膜一下\(GXZ\)再说 我们先把序列从小到大排序,然后分情况讨论 无解是不存在的,从小到大输出所有数肯定可行 情况一,如果\(a[mid]=a[mid+1]\),因为最终的中位数也是它们 ...

  5. 【UOJ #280】【UTR #2】题目难度提升

    http://uoj.ac/problem/280 非常难想的贪心,用set\(O(nlogn)\). 调了一天qwq. 题解 #include<set> #include<cstd ...

  6. 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp

    题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...

  7. bzoj4165 矩阵 堆维护多路归并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4165 题解 大概多路归并是最很重要的知识点了吧,近几年考察也挺多的(虽然都是作为签到题的). ...

  8. [UOJ#268]. 【清华集训2016】数据交互[动态dp+可删堆维护最长链]

    题意 给出 \(n\) 个点的树,每个时刻可能出现一条路径 \(A_i\) 或者之前出现的某条路径 \(A_i\) 消失,每条路径有一个权值,求出在每个时刻过后能够找到的权值最大的路径(指所有和该路径 ...

  9. POJ 2010 Moo University - Financial Aid(堆维护滑窗kth,二分)

    按照score排序,贪心,从左到右用堆维护并且记录前面的最小N/2个花费之和. 然后从右向左枚举中位数,维护N/2个数之和加上并判断是否满足条件.(stl的队列没有clear(),只能一个一个pop. ...

随机推荐

  1. leetcode-mid-math-371. Sum of Two Integers-NO-???

    mycode: 没思路啊...二级制四则运算不熟悉... 参考: 既然不能使用加法和减法,那么就用位操作.下面以计算5+4的例子说明如何用位操作实现加法: 1. 用二进制表示两个加数,a=5=0101 ...

  2. 一、Jmeter启动报错:Could not initialize class org.apache.jmeter.gui.util.MenuFactory

    1.下载: plugins-manager.jar 包 2.地址:https://jmeter-plugins.org/install/Install/ 3.将jar包放到lib/ext 4.重启jm ...

  3. 二、启动一款app演示

    一.下载aapt包 1. aapt即Android Asset Packaging Tool,在SDK的build-tools目录下.该工具可以查看apk包名和launcherActivity 2.打 ...

  4. 二、robotframework接口测试-常用关键字介绍

    1.常用关键字介绍: a. 打印:log                                                  用法:log   打印内容 ---------------- ...

  5. HTTPS 证书制作及使用

    一 证书的制作 进入jdk/bin,使用keytools.exe制作证书. 1.创建keystore 创建一个别名为serverkeystore的证书,该证书存放在名为server.keystore的 ...

  6. sql进阶练习题

    student SNO    SNAME    SAGE    SSEX01    赵雷    1990-01-01 00:00:00    男02    钱电    1990-12-21 00:00 ...

  7. Unity3D(C#)连接SQL Server2008

    首先部署安装sql server2008,添加Sql Manager. Unity3D连接需要在Unity2017\Editor\Data\Mono\lib\mono\unity文件下找到4个头文件l ...

  8. 宝塔面板修改用户名和密码报错:TypeError: cannot concatenate 'str' and 'NoneType' objects

    [root@dapao~]# bt 14 正在执行(14)... ================================================================== ...

  9. Java中的内存泄露 和 JVM GC(垃圾回收机制)

    一.什么是Java中的内存泄露? 在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点, 首先,这些对象是可达的,即在有向图中,存在通路可以与其相连:其次,这些对象是无用的,即程序以 ...

  10. Grass Planting

    大致题意: 维护一棵树,支持两种操作: P x y x到y路径上的每条边的值+1:Q x y 询问x到y路径上所有边的值的和.Input第一行两个正整数,N,M表示点数和操作数:接下来N-1行每行两个 ...