C. Phoenix and Towers
Posted Lnn.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C. Phoenix and Towers相关的知识,希望对你有一定的参考价值。
前言:其实就是合并果子。
C. Phoenix and Towers
题目类型:贪心,优先队列
解析:
对于把n个数放到m个位置上的问题,我们可以先考虑简化版本:选m个数放到m个位置上。显然,m个数,任意两个数的差不超过x,即最大和最小的数差不超过x,那么这m个数就是原数组中最小的m个数。这一部分sort处理。
接下来考虑,在处理好的m个数中,添加一个数。那么现在有m+1个数,我们可以取其二相加,贪心一下,选两个最小值相加。不断重复这个操作。便得到正解。这部分用优先队列维护。
可以证明一下(我懒不细说了 ),不取最小的相加,则最小值比原来小,并且最大值可能会更大,差也会更大。
要构造的话,麻烦一点,模拟指针,可以记录优先队列的结点的最早加进来的下标first_id,最后加进来的下标last_id,合并结点的时候让其中一个的first_id -> 另一个的last_id。然后开个last[]记录每个点的前一个点,初始为0。
code:
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,t,m,x,last[101010],ans[101010];
struct seq
{
int id,val;
}a[101010];
struct num
{
int val,last_id,first_id;
friend bool operator < (const num &a1,const num &a2){
return a1.val>a2.val;
}
};
priority_queue<num>q;
int cmp(seq &a1,seq &a2)
{
return a1.val < a2.val;
}
int main()
{
ios::sync_with_stdio(false);
cin >> t ;
while(t--){
cin >> n >> m >> x ;
for(int i = 1 ; i <= n ; ++i)
cin >> a[i].val , a[i].id = i;
sort(a+1,a+1+n,cmp);
for(int i = 1 ; i <= n ; ++i){
q.push({a[i].val,i,i});
if(i>m){
num top1 = q.top();
q.pop();
num top2 = q.top();
q.pop();
int new_num = top1.val + top2.val;
last[top1.first_id] = top2.last_id;
q.push({new_num,top1.last_id,top2.first_id});
}
}
num top = q.top();
int cnt = 0 , minn = top.val , maxx;
while(!q.empty()){
++cnt;
num top = q.top();
int id = top.last_id;
while(id){
ans[a[id].id] = cnt;
id = last[id];
}
if(q.size() == 1)
maxx = top.val;
q.pop();
}
if(maxx - minn > x)cout << "NO" << endl ;
else {
cout << "YES" << endl ;
for(int i = 1 ; i <= n ; ++i)
cout << ans[i] << " " ;
cout << endl ;
}
for(int i = 1 ; i <= n ; ++i)
last[i] = 0;
}
return 0;
}
以上是关于C. Phoenix and Towers的主要内容,如果未能解决你的问题,请参考以下文章
C. Phoenix and Towers1400 / 贪心
Codeforces Global Round 14 C. Phoenix and Towers
Codeforces Global Round 14-C. Phoenix and Towers-堆模拟