【uoj#280】[UTR #2]题目难度提升 对顶堆+STL-set
给出 $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的更多相关文章
- 【UTR #2】[UOJ#278]题目排列顺序 [UOJ#279]题目交流通道 [UOJ#280]题目难度提升
[UOJ#278][UTR #2]题目排列顺序 试题描述 “又要出题了.” 宇宙出题中心主任 —— 吉米多出题斯基,坐在办公桌前策划即将到来的 UOI. 这场比赛有 n 道题,吉米多出题斯基需要决定这 ...
- 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 ...
- uoj280 【UTR #2】题目难度提升 堆维护中位数+set
题目传送门 http://uoj.ac/problem/280 题解 这道题很妙啊. 这种题目如果给予选手足够的时间,每一个选手应该都能做出来. 大概就是核心思路看上去很简单,但是想要推出来并不简单. ...
- 洛谷 - P1801 - 黑匣子 - 对顶堆
这道题是提高+省选-的难度,做出来的话对数据结构题目的理解会增加很多. 可以使用一种叫做对顶堆的东西,对顶堆是在线维护第n小的logn的算法.大概的思路是,假如我们要找的是第n小,我们就维护一个大小为 ...
- 【Luogu P1168】【Luogu P1801&UVA 501】中位数&黑匣子(Black Box)——对顶堆相关
Luogu P1168 Luogu P1801 UVA 501(洛谷Remote Judge) 前置知识:堆.优先队列STL的使用 对顶堆 是一种在线维护第\(k\)小的算法. 其实就是开两个堆,一个 ...
- poj3784(对顶堆)
题意:多组数据,让你求出1~i(i为奇数&&i<=n)的中位数 思路:首先复杂度必为O(n)或O(nlogn)的(数据范围) 思索,如果题目要求1次中位数,好求!排个序,取a[( ...
- hdu3282 链表或者对顶堆
维护序列的动态中位数 第一次用链表做题..感觉指针指来指去也挺麻烦的.. 本题链表解法就是用数组模拟出一个链表,然后离线输入所有数,排序,按照输入顺序在链表里删除元素,一次性删掉两个,然后中位数指针对 ...
- hdu4261 Estimation[暴力dp+对顶堆]
https://vjudge.net/problem/HDU-4261 对于一个长2000的数列划分最多25个块,每块代价为块内每个数与块内中位数差的绝对值之和,求最小总代价. 套路化地,设$f[i] ...
随机推荐
- list add() 和 addall()的区别
http://blog.tianya.cn/post-4777591 如果有多个已经被实例化的List 集合,想要把他们组合成一个整体,并且,这里必须直接使用List 自身提供的一个方法List.ad ...
- Springboot日记——核心编码篇
背景吐槽:想要让自己进阶一下,一定要有个可以拿出来秀的东西,所以要尝试写一个属于自己的网站或者平台.因此,我大概的看了一下springboot+Mybatis-plus+... 框架介绍 通常 SSM ...
- QTP日常积累
1.init同步测试对象 同步测试对象: CODE: Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit(" ...
- Centos7 zabbix 分布式监控
分布式监控 zabbix Server ===> zabbix agent (只能同一个局域网监控) 分布式监控: a. 分担压力,降低负载 b. 多机房 ...
- dirname命令详解
基础命令学习目录首页 原文链接:https://blog.csdn.net/xiaofei125145/article/details/50620281 示例一 来自手册页的例子 $ dirname ...
- groupadd命令详解
基础命令学习目录首页 原文链接:https://wtj6891.iteye.com/blog/2096076 groupadd创建组群 使用groupadd命令可以在系统中创建组群账户 语法: gro ...
- 【Oracle】存储过程在字符串单引号'内拼接单引号'
http://blog.csdn.net/u011704894/article/details/44976557 一般变量里面接3个单引号 eg: 'DELETE FROM RDM_SUPP_DATA ...
- Daily Srum 10.30
Android那一组打算用SQL Server这个关系型数据库,而王鹿鸣他们一组却是依赖于Hbase,这是一件很麻烦的事,所以我打算在这两方面都建立一个数据库.虽然挺麻烦,但是还是为了扩展性所做的必要 ...
- prototype原型(待完善)
模式:prototype 解决向量的深浅克隆 #pragma once #ifndef _PROTOTYPE_H_ #define _PROTOTYPE_H_ class Prototype{ pu ...
- FileInputStream 读取文件数据的输入字节流
package com.inputstream; /* File类: 用于描述一个文件或者文件夹的. 通过File对象我们可以读取文件或者文件夹的属性数据,如果我们需要读取文件的内容数据,那么我们需要 ...