uoj280 【UTR #2】题目难度提升 堆维护中位数+set
题目传送门
题解
这道题很妙啊。
这种题目如果给予选手足够的时间,每一个选手应该都能做出来。
大概就是核心思路看上去很简单,但是想要推出来并不简单。
首先考虑如果没有重复的元素应该怎么做。
第一个数应该就是最小值。
在没有重复元素的时候,新加入一个数想要保证中位数不下降就必须要满足这个数大于等于前面的中位数。
所以选择加入某个数的时候的判断条件就是加入这个数以后,剩下的最小的数比中位数大。
具体实现的时候,可以先取出这个最小的数。如果前面的元素数量是奇数,那么加入它以后中位数是中间两个数的平均值,所以需要讨论这个最小的数和之前中位数的关系。如果大于之前的中位数,那么我们可以直接选择剩下的数里面最大的——因为不管加进去谁,以后的中位数都没有这个最小的数大,所以可以直接放心地加入最大的;否则,假设之前的中位数为 \(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的更多相关文章
- 【uoj#280】[UTR #2]题目难度提升 对顶堆+STL-set
题目描述 给出 $n$ 个数 $a_1,a_2,...,a_n$ ,将其排为序列 $\{p_i\}$ ,满足 $\{前\ i\ 个数的中位数\}$ 单调不降.求字典序最大的 $\{p_i\}$ . 其 ...
- 【UTR #2】[UOJ#278]题目排列顺序 [UOJ#279]题目交流通道 [UOJ#280]题目难度提升
[UOJ#278][UTR #2]题目排列顺序 试题描述 “又要出题了.” 宇宙出题中心主任 —— 吉米多出题斯基,坐在办公桌前策划即将到来的 UOI. 这场比赛有 n 道题,吉米多出题斯基需要决定这 ...
- 洛谷 P3644 [APIO2015]八邻旁之桥(对顶堆维护中位数)
题面传送门 题意: 一条河将大地分为 \(A,B\) 两个部分.两部分均可视为一根数轴. 有 \(n\) 名工人,第 \(i\) 名的家在 \(x_i\) 区域的 \(a_i\) 位置,公司在 \(y ...
- uoj#280. 【UTR #2】题目难度提升(构造)
传送门 咱先膜一下\(GXZ\)再说 我们先把序列从小到大排序,然后分情况讨论 无解是不存在的,从小到大输出所有数肯定可行 情况一,如果\(a[mid]=a[mid+1]\),因为最终的中位数也是它们 ...
- 【UOJ #280】【UTR #2】题目难度提升
http://uoj.ac/problem/280 非常难想的贪心,用set\(O(nlogn)\). 调了一天qwq. 题解 #include<set> #include<cstd ...
- 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp
题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...
- bzoj4165 矩阵 堆维护多路归并
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4165 题解 大概多路归并是最很重要的知识点了吧,近几年考察也挺多的(虽然都是作为签到题的). ...
- [UOJ#268]. 【清华集训2016】数据交互[动态dp+可删堆维护最长链]
题意 给出 \(n\) 个点的树,每个时刻可能出现一条路径 \(A_i\) 或者之前出现的某条路径 \(A_i\) 消失,每条路径有一个权值,求出在每个时刻过后能够找到的权值最大的路径(指所有和该路径 ...
- POJ 2010 Moo University - Financial Aid(堆维护滑窗kth,二分)
按照score排序,贪心,从左到右用堆维护并且记录前面的最小N/2个花费之和. 然后从右向左枚举中位数,维护N/2个数之和加上并判断是否满足条件.(stl的队列没有clear(),只能一个一个pop. ...
随机推荐
- Spring的Ioc理解
1.Ioc=控制反转和依赖注入(DI),两个是一回事 控制反转的好处: 把对象的创建和依赖定义在xml中,改变子类的实现变得很简单 控制反转减轻了对象之间的耦合度,减轻了对象之间的依赖关系,增加了系统 ...
- 生成base64位图片验证码
import org.springframework.util.Base64Utils; import javax.imageio.ImageIO; import java.awt.*; import ...
- mac 外接显示屏的坑
概述 工作中使用 Mac 外接显示屏,有时会出现闪屏然后黑屏的现象,之前都没有找到原因,今天终于找到了,记录下来,供以后参考,相信对其他人也有用. 参考资料: Macbook外接显示器设置教程 问题 ...
- 爬虫三之beautifulsoup
基本使用 from bs4 import BeautifulSoup soup = BeautifulSoup(html#,'lxml','xml','html5lib') soup.prettify ...
- 13.DoS防御----BeEF浏览器渗透----暴力破解之美杜莎---DNS指南
DoS防御 启用ICMP,UDP,TCP泛洪过滤 登录路由器管理后台 高级-安全部分 BeEF浏览器渗透 用kali进行客户端攻击 钓鱼攻击 打开beef 浏览器打开beef cd /usr/shar ...
- BCD与ASCII码互转-C语言实现
/*BCD 与 ASCII码转换*/ /******************************************************************* 函数名: asc2bc ...
- servlet3.0文件上传与下载
描述:文件上传与下载是在JavaEE中常见的功能,实现文件上传与下载的方式有多种,其中文件上传的方式有: (1)commons-fileupload: (2)Servlet 3.0 实现文件上传 (3 ...
- Java - Java Mail邮件开发(3)spring +Java Mail + Velocity
1.spring + Java Mail + Velocity 项目结构: 注意:用户包中引入各包的顺序问题.如velocity-2.1. beans.xml <?xml version=&qu ...
- JS中同步与异步
不讲过多定义,举两个例子说明下 例一: console.log(100); setTimeout(function(){ console.log(200); },1000); console.log( ...
- Lucky Boy
Lucky Boy Problem Description Recently, Lur have a good luck. He is also the cleverest boy in his sc ...