#280. UTR #2题目难度提升
Posted r-q-r-q
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#280. UTR #2题目难度提升相关的知识,希望对你有一定的参考价值。
题目描述
最终吉米多出题斯基没有找到优质的题目,于是高产的吉米多出题斯基决定自己出一道。
首先,吉米多出题斯基脑洞了一道难度为 h1 的题目,然而吉米多出题斯基觉得太水了,于是把这题稍微改了改变成了一道难度为 h2 的。然而吉米多出题斯基还是觉得太水了,又稍微改了改变成了难度为 h3 的。如此进行下去吉米多出题斯基脑洞出了 n 个版本的题目,难度分别为 h1,…,hn。
由于吉米多出题斯基在脑洞的时候只是随便改了改题目条件,所以每次改题并不一定会变难。但神奇的是,每次产生一个新版本的题目后,吉米多出题斯基手上所有版本的题目难度的中位数不会降低。
很快吉米多出题斯基出好了题,造好了 UOI,选手们纷纷阵亡。多年后吉米多出题斯基再看到自己曾经出的这道题时感叹道:“都是回忆啊……”
可是吉米多出题斯基突然发现自己只记得脑洞过程产生的 n 个版本难度是 a1,…,an,却不记得每个 ai 对应的是第几个版本了。
吉米多出题斯基日理万机没有时间再细想了,于是他找到了你 —— 风璃殇做不出题耶维奇,请你帮助吉米多出题斯基把 a1,…,an 排列顺序,给出一组满足条件且字典序最大的 h1,…,hn 吧!
对于一个数列 v1,…,vm,若 m 为奇数则定义中位数为从小到大第 ?m/2? 的数;若 m 为偶数则定义中位数为从小到大第 m/2 和第 m/2+1 的数的平均值。
输入格式
第一行一个正整数 n。
接下来一行 n 个整数 a1,…,an。
输出格式
一行,n 个整数表示你找到的字典序最大的 h1,…,hn。
如果无解,输出卖萌表情 "QwQ"。
样例一
input
5
1 2 3 4 5
output
1 3 2 5 4
explanation
中位数依次为:{1,2,2,2.5,3}。
样例二
input
8
1 2 2 3 3 3 4 4
output
3 3 4 3 4 2 2 1
样例三
见样例数据下载。
限制与约定
子任务 分值 n 其他约定
1 10 1≤n≤10 无
2 10 1≤n≤100 无
3 20 1≤n≤2000 无
4 30 1≤n≤105 ai 互不相同
5 30 1≤n≤105 无
对于所有数据,满足 1≤ai≤109。
时间限制:1s
空间限制:256MB
对顶堆
这是一个大型分类讨论现场。。。
讲a 从小到大排序
若 a[mid] = a[mid+1]
那么左一个右一个直接选完,即可得到最优解。
否则 往左扫,直到扫到有挨着相同的。
也是左一个右一个,但是肯定有剩余。
把已经选了的放入(对顶)堆里,维护中位数
没选的放入multiset中。
分类讨论即可。。。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<bitset>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 1e5+10;
inline int read()
{
register int x = 0 , f = 0; register char c = getchar();
while(c < ‘0‘ || c > ‘9‘) f |= c == ‘-‘ , c = getchar();
while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) + (x << 1) + c - ‘0‘ , c = getchar();
return f ? -x : x;
}
int n;
int a[N] , vis[N];
priority_queue<int> A , B;
multiset<int> s;
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() - 1 > B.size()) B.push(-A.top()) , A.pop();
return ;
}
void solve()
{
sort(a + 1 , a + 1 + n); int mid = (n + 1) >> 1;
if(a[mid] == a[mid + 1])
{
while(mid < n && a[mid] == a[mid + 1]) mid++;
cout << a[mid] << ‘ ‘; int p = mid - 1 , q = n;
while(p || q > mid)
{
if(p) cout << a[p--] << ‘ ‘;
if(q > mid) cout << a[q--] << ‘ ‘;
}
cout << ‘
‘; return ;
}
while(mid > 1 && a[mid] != a[mid - 1]) mid--;
vis[mid] = 1; cout << a[mid] << ‘ ‘; int p = mid - 1 , q = n;
while(p && q > mid) cout << a[p] << ‘ ‘ , vis[p--] = 1 , cout << a[q] << ‘ ‘ , vis[q--] = 1;
for(int i = 1 ; i <= n ; ++i) if(!vis[i]) s.insert(a[i]); else push(a[i]);
while(!s.empty()) // 满足堆里的中位数 <= 没选的的最小值
{
int p = *s.begin() , q;
if(A.size() == B.size())
{
if(p >= -B.top()) q = *--s.end(); // 最小值比中位数大。怎么选也合法,选最大的字典序更大
else q = *s.begin(); // 再不选那个*s.begin就 < 堆中的最小值。
}
else
{
if(!B.empty() && p * 2 >= A.top() - B.top()) q = *--s.end(); // 同上
else q = *--s.upper_bound(p * 2 - A.top()); // 偶数时不一定选他自己,可以选中间两个数的中间的数,比如2 , 10 , 可以不选3,选6, 3可以之后再选
}
cout << q << ‘ ‘; s.erase(s.find(q)); push(q); // s.erase(find(q)) 是只删一个
}
return ;
}
int main()
{
freopen("c.in" , "r" , stdin);
freopen("c.out" , "w" , stdout);
n = read();
for(int i = 1 ; i <= n ; ++i) a[i] = read();
solve();
fclose(stdin); fclose(stdout);
return 0;
}
/*
10
1 2 2 3 3 3 4 4 5 6
*/
以上是关于#280. UTR #2题目难度提升的主要内容,如果未能解决你的问题,请参考以下文章