题目描述

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

其中,对于一个长度为 $m$ 的数列,若 $m$ 为奇数,则中位数为从小到大第 $\lceil\frac m2\rceil$ 大的数;若 $m$ 为偶数,则中位数为从小到大第 $\frac m2$ 大和第 $\frac m2+1$ 大的数的平均值。


题解

对顶堆+STL-set

显然如果已经知道了这个数列的一部分,剩下的一定是每次加入大于等于中位数的数。

那么如何确定这一“部分呢”?将 $a$ 从小到大排序,然后:

  • 如果 $a_{\lceil\frac n2\rceil}=a_{\lceil\frac n2\rceil+1}$ ,则可以让任何时刻中位数都等于 $a_{\lceil\frac n2\rceil}$ ,找到最大的 $k$ 使得 $a_k+1=a_{\lceil\frac n2\rceil}$ ,按照 $k,k+1,k-1,k+2,k-2,...$ 的顺序选择完整个数列即可得到最优解,显然任何时刻中位数都相等。没有考虑到这种情况可以得到60分。
  • 否则如果存在 $k<\lceil\frac n2\rceil$ 且 $a_k=a_{k+1}$ ,则按照 $k,k+1,k-1,k+2,k-2,...$ 的顺序选择,直到前面没有数可以取,这个过程中位数都相等。没有考虑到这种情况只能得到所有数互不相同的40分。
  • 否则选择第一个数。

然后使用multiset保证每次删除后最小的数大于等于中位数,使用对顶堆维护中位数即可。

对顶堆:使用大根堆维护较小数,使用小根堆维护大数,保证两个堆的大小差不超过1。显然中位数可以直接从两个堆的堆顶元素得到。

时间复杂度 $O(n\log n)$ 。

#include <set>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
multiset<int> s;
priority_queue<int> A , B;
int a[N] , v[N];
inline void push(int x)
{
if(A.empty() || x <= A.top()) A.push(x);
else B.push(-x);
if(A.size() < B.size()) A.push(-B.top()) , B.pop();
if(A.size() - B.size() > 1) B.push(-A.top()) , A.pop();
}
int main()
{
int n , i , p , q , mid;
scanf("%d" , &n);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]);
sort(a + 1 , a + n + 1) , mid = (n + 1) >> 1;
if(a[mid] == a[mid + 1])
{
while(mid < n && a[mid] == a[mid + 1]) mid ++ ;
printf("%d" , a[mid]) , p = mid - 1 , q = n;
while(p || q > mid)
{
if(p) printf(" %d" , a[p -- ]);
if(q > mid) printf(" %d" , a[q -- ]);
}
return 0;
}
while(mid > 1 && a[mid] != a[mid - 1]) mid -- ;
printf("%d" , a[mid]) , v[mid] = 1 , p = mid - 1 , q = n;
while(p && q > mid) printf(" %d" , a[p]) , v[p -- ] = 1 , printf(" %d" , a[q]) , v[q -- ] = 1;
for(i = 1 ; i <= n ; i ++ )
{
if(v[i]) push(a[i]);
else s.insert(a[i]);
}
while(!s.empty())
{
p = *s.begin();
if(A.size() == B.size())
{
if(p >= -B.top()) q = *--s.end();
else q = *s.begin();
}
else
{
if(!B.empty() && p * 2 >= A.top() - B.top()) q = *--s.end();
else q = *--s.upper_bound(p * 2 - A.top());
}
printf(" %d" , q) , s.erase(s.find(q)) , push(q);
}
return 0;
}

【uoj#280】[UTR #2]题目难度提升 对顶堆+STL-set的更多相关文章

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

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

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

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

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

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

  4. uoj280 【UTR #2】题目难度提升 堆维护中位数+set

    题目传送门 http://uoj.ac/problem/280 题解 这道题很妙啊. 这种题目如果给予选手足够的时间,每一个选手应该都能做出来. 大概就是核心思路看上去很简单,但是想要推出来并不简单. ...

  5. 洛谷 - P1801 - 黑匣子 - 对顶堆

    这道题是提高+省选-的难度,做出来的话对数据结构题目的理解会增加很多. 可以使用一种叫做对顶堆的东西,对顶堆是在线维护第n小的logn的算法.大概的思路是,假如我们要找的是第n小,我们就维护一个大小为 ...

  6. 【Luogu P1168】【Luogu P1801&UVA 501】中位数&黑匣子(Black Box)——对顶堆相关

    Luogu P1168 Luogu P1801 UVA 501(洛谷Remote Judge) 前置知识:堆.优先队列STL的使用 对顶堆 是一种在线维护第\(k\)小的算法. 其实就是开两个堆,一个 ...

  7. poj3784(对顶堆)

    题意:多组数据,让你求出1~i(i为奇数&&i<=n)的中位数 思路:首先复杂度必为O(n)或O(nlogn)的(数据范围) 思索,如果题目要求1次中位数,好求!排个序,取a[( ...

  8. hdu3282 链表或者对顶堆

    维护序列的动态中位数 第一次用链表做题..感觉指针指来指去也挺麻烦的.. 本题链表解法就是用数组模拟出一个链表,然后离线输入所有数,排序,按照输入顺序在链表里删除元素,一次性删掉两个,然后中位数指针对 ...

  9. hdu4261 Estimation[暴力dp+对顶堆]

    https://vjudge.net/problem/HDU-4261 对于一个长2000的数列划分最多25个块,每块代价为块内每个数与块内中位数差的绝对值之和,求最小总代价. 套路化地,设$f[i] ...

随机推荐

  1. BootStap学习笔记(2)

    学习该内容之前可能会用到的内容: css属性Font-Weight:如果数字为700就是加粗的.或者更粗的为bolder,更细的是lighter. html Cite标签定义文档的引用,默认字体以斜体 ...

  2. Assert.notNull(sessionUser);

    rg.springframework.util.Assert Assert翻译为中文为"断言".就是断定某一个实际的值就为自己预期想得到的,如果不一样就抛出异常.

  3. 如何实现Canvas图像的拖拽、点击等操作

    上一篇Canvas的博文写完后,有位朋友希望能对Canvas绘制出来的图像进行点击.拖拽等操作,因为Canvas绘制出的图像能很好的美化.好像是想做炉石什么的游戏,我也没玩过. Canvas在我的理解 ...

  4. 并发系列(二)----Java内存模型

    一 简介 在并发编程中,两个线程(A.B)同时操作一个普通变量的时候会出现线程A在操作变量时线程B也将变量操作了,此时线程A是无法感知变量发生变化的,造成变量改变错误.更据以上例子我们需要解决的问题就 ...

  5. Unity扩展编辑器四

    Inspector视图中的get/set使用 get  set使用起来很方便,但编辑时,在Inspector视图中问题就来了,因为get/set的属性即使是public了,但是在Inspector视图 ...

  6. Netty源码分析第5章(ByteBuf)---->第1节: AbstractByteBuf

    Netty源码分析第五章: ByteBuf 概述: 熟悉Nio的小伙伴应该对jdk底层byteBuffer不会陌生, 也就是字节缓冲区, 主要用于对网络底层io进行读写, 当channel中有数据时, ...

  7. .NetCore下使用EF DbFirst操作MySql

    新建.NetCore的控制台项目 使用Nuget安装Pomelo.entityframeworkcore.mysql 工程右键--->编辑.csproj文件,把以下内容写入到工程文件 <I ...

  8. Hyperledger Fabric 1.2 --- Chaincode Operator 解读和测试(二)

    本文接上一节是测试部分 搭建一个模拟测试环境 作者将fabric release1.2工程中的 example-e2e进行了改造来进行本次实验: (1)首先我们将examples/e2e_cli/sc ...

  9. Python模块xlwt对excel进行写入操作

    python常用模块目录 1.安装 $ pip install xlwt 2.创建表格和工作表单写入内容 例子: import xlwt # 创建一个workbook 设置编码 workbook = ...

  10. 欢迎来怼--第三十六次Scrum会议

    一.小组信息 队名:欢迎来怼 小组成员 队长:田继平 成员:李圆圆,葛美义,王伟东,姜珊,邵朔,阚博文 小组照片 二.开会信息 时间:2017/12/1 11:35~11:55,总计20min. 地点 ...