一.题目链接:
荷马史诗
二.题目大意:
给出每个单词的出现次数.
现要求用 k 进制数设计前缀编码.
使得文章总长度最小.
输出文章总长度的最小值和最长单词编码的最小长度.
三.分析:
很容易想到哈弗曼树.
这里是 k 叉哈弗曼树,对应 0 ~ k - 1.
有一点需要注意:初始有 n 颗树,每次合并会减少 k - 1 棵树.
为了方便,可以加入若干个 0 节点,使得 (n - 1) % (k - 1) == 0.
四.代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long
#define ull unsigned long long
using namespace std;
const int M = (int)1e5;
const int mod = 99991;
const int inf = 0x3f3f3f3f;
priority_queue < pair<ll, ll> > q;
int main()
{
int n, k;
scanf("%d %d", &n, &k);
ll x;
for(int i = 0; i < n; ++i)
{
scanf("%lld", &x);
q.push(make_pair(-x, 0));
}
while((n - 1) % (k - 1))
{
n++;
q.push(make_pair(0, 0));
}
ll sum = 0, w, h;
while(q.size() != 1)
{
w = h = 0;
for(int i = 0; i < k; ++i)
{
w += q.top().first;
h = min(h, q.top().second);
q.pop();
}
sum += w;
q.push(make_pair(w, h - 1));
}
printf("%lld\n%lld\n", -sum, -q.top().second);
return 0;
}