B - 多元Huffman编码问题

Description
在一个操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次至少选2 堆最多选k堆石子合并成新的一堆,合并的费用为新的一堆的石子数。试设计一个算法,计算出将n堆石子合并成一堆的最大总费用和最小总费用。
对于给定n堆石子,计算合并成一堆的最大总费用和最小总费用。

Input
输入数据的第1 行有2 个正整数n和k(n≤100000,k≤10000),表示有n堆石子,每次至少选2 堆最多选k堆石子合并。第2 行有n个数(每个数均不超过 100),分别表示每堆石子的个数。

Output
将计算出的最大总费用和最小总费用输出,两个整数之间用空格分开。

Sample
Input 
7 3
45 13 12 16 9 5 22
Output 
593 199
Hint
请注意数据范围是否可能爆 int。
优先队列:
priority_queue<int,vector<int>,greater<int> >q;//从小往大排序
priority_queue<int,vector<int>,less<int> >p;//从大往小排序
优先队列默认从大到小排序,即:
priority_queue<int>p;


/*最大花费:两个两个合并最大的;
最小花费:k个(最多个)合并最小的*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
ll a[maxn];
ll k,n;
ll ans1,ans2;
priority_queue<ll>que;//从大到小,一次合并两个,计算最多花费
priority_queue<ll,vector<ll>,greater<ll> >q;//从小往大,一次合并k个,计算最小花费

int main()
{
    cin>>n>>k;
    for(ll i=1;i<=n;i++){
        cin>>a[i];
        que.push(a[i]);
        q.push(a[i]);
    }

    while( que.size()>1 ){
        ll num = 0;
        ll ans = 0;
        while( !que.empty() && num<=1 ){//num控制取两次当前栈最大值
            ans += que.top();
            que.pop();
            num++;
        }
        ans1 += ans;//ans1记录最大花费
        que.push(ans);//把合并后的值再次放入队列
    }

    while( q.size()%(k-1)!=1 ) q.push(0);//每次合并k个再添进去1个,相当于每次去掉(k-1)个,合并到最后只剩下1个节点结束。也就是说一共要有%(k-1)=1个节点
    while( q.size()>1 ){
        ll num=0;
        ll ans = 0;
        while( !q.empty() && num<=(k-1)){
            ans += q.top();
            q.pop();
            num++;
        }
        ans2 += ans;
        q.push(ans);
    }

    printf("%lld %lld\n",ans1,ans2);
    return 0;
}
©️2020 CSDN 皮肤主题: 终极编程指南 设计师:CSDN官方博客 返回首页