一.题目链接:

荷马史诗

二.题目大意:

给出每个单词的出现次数.

现要求用 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;
}