思路:观看此题,脑海中第一时间就想到了trie树;
方案:构建出一个类似于trie树的树,之后对其进行移动子树操作,使整棵树的最大深度最小;
使用结构:大根堆,维护一个每个子节点的数值与深度,从深到浅将每个节点的子节点的数值合并在父节点上,最后输出根的深度;
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
typedef long long LL;
struct GG {
LL val, dep;
bool operator<(const GG& t) const {
if (val == t.val)
return dep > t.dep;//构建一颗树,从深到浅
return val > t.val;//将数值排序,使其成为最优解
}
};
LL res = 0, cnt = 0;
priority_queue<GG> heap;//堆来维护
int main() {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++) {
LL t;
cin >> t;
heap.push({ t, 0 });//将节点加入堆
}
cnt = n;
if ((n - 1) % (k - 1) != 0)
cnt += k - 1 - (n - 1) % (k - 1);//剪切子树操作
for (int i = 1; i <= cnt - n; i++) {
heap.push({ 0, 0 });//加入空节点,使其平衡
}
while (cnt != 1) {
LL val = 0, deep = 0;
for (int i = 1; i <= k; i++) {
auto tot = heap.top();
val += tot.val;
deep = max(deep, tot.dep);//合并
heap.pop();
}
heap.push({ val, deep + 1 });
cnt -= k - 1;
res += val;//答案
}
cout << res << endl << heap.top().dep << endl;
return 0;
}