题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=4198
分析
Huffman编码,每次取出权值最小的 k k k 个点进行合并。
为了保证之后取时不会不足 k k k 个点而使答案不最优,要加入一些权值为 0 0 0 的点“占位”。
题目要求最长的字符串尽量短,每个节点除了权值再维护下合并次数即可,取时权值一样则取合并次数少的。
AC代码
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
inline ll read() {
ll num = 0;
char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9')
num = num * 10 + c - '0', c = getchar();
return num;
}
const int maxn = 1e5 + 5;
struct Node {
ll v, t;
Node(ll v = 0, ll t = -1) : v(v), t(t) {}
bool operator < (const Node& rhs) const {
if (v == rhs.v) return t < rhs.t;
return v < rhs.v;
}
};
struct Heap {
int tot;
Node h[maxn];
Heap(int t = 0) : tot(t) {}
void up(int p) {
while (p > 1) {
if (h[p] < h[p / 2]) swap(h[p], h[p / 2]), p /= 2;
else break;
}
}
void down(int p) {
while (2 * p <= tot) {
int q = 2 * p;
if (q + 1 <= tot && h[q + 1] < h[q]) ++q;
if (h[q] < h[p]) swap(h[q], h[p]), p = q;
else break;
}
}
void insert(Node x) {
h[++tot] = x;
up(tot);
}
Node top() {
return h[1];
}
void remove(int p = 1) {
h[p] = h[tot--];
up(p), down(p);
}
} h;
int main() {
int n = read(), k = read();
ll ans = 0;
for (int i = 1; i <= n; ++i) h.insert(Node(read(), 0));
while ((n - 1) % (k - 1)) h.insert(Node(0, 0)), ++n;
while (h.tot > 1) {
ll sum = 0, len = 0;
for (int i = 1; i <= k; ++i) {
sum += h.top().v, len = max(len, h.top().t);
h.remove();
}
h.insert(Node(sum, len + 1));
ans += sum;
}
printf("%lld\n%lld", ans, h.top().t);
return 0;
}