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;
}

猜你喜欢

转载自blog.csdn.net/m0_45699242/article/details/116382462