Description

追逐影子的人, 自己就是影子.----荷马

Allison 最近迷上了文学. 她喜欢在一个慵懒的午后, 细细地品上一杯卡布奇诺, 静静地阅读她爱不释手的《荷马史诗》. 但是由《奥德赛》和《伊利亚特》组成的鸿篇巨制 《荷马史诗》实在是太长了, Allison 想通过一种编码方式使得它变得短一些.

一部《荷马史诗》中有 \(n\) 种不同的单词, 从 \(1\)\(n\) 进行编号. 其中第 \(i\) 种单词出现的总次数为 \(w_i\). Allison 想要用 \(k\) 进制串 \(s_i\) 来替换第 \(i\) 种单词, 使得 其满足如下要求:

对于任意的 \(1 \leq i, j \leq n, i \neq j\), 都有:\(s_i\) 不是 \(s_j\) 的前缀.

现在 Allison 想要知道, 如何选择 \(s_i\), 才能使替换以后得到的新的《荷马史诗》长度 最小. 在确保总长度最小的情况下, Allison 还想知道最长的 \(s_i\) 的最短长度是多少?

一个字符串被称为 \(k\) 进制字符串, 当且仅当它的每个字符是 \(0\)\(k - 1\) 之间 (包括 \(0\)\(k - 1\)) 的整数.

字符串 \(Str_1\) 被称为字符串 \(Str_2\) 的前缀, 当且仅当: 存在 \(1 \leq t \leq m\), 使得 \(Str_1 = Str_2[1 \ldots t]\). 其中,\(m\) 是字符串 \(Str_2\) 的长度,\(Str_2[1 \ldots t]\) 表示 \(Str_2\) 的前 \(t\) 个字符组成的字符串.

Input

输入文件的第 \(1\) 行包含 \(2\) 个正整数 \(n, k\), 中间用单个空格隔开, 表示共有 \(n\) 种单词, 需要使用 \(k\) 进制字符串进行替换.

接下来 \(n\) 行, 第 \(i+1\) 行包含 \(1\) 个非负整数 \(w_i\), 表示第 \(i\) 种单词的出现次数.

Output

输出文件包括 \(2\) 行.

\(1\) 行输出 \(1\) 个整数, 为《荷马史诗》经过重新编码以后的最短长度.

\(2\) 行输出 \(1\) 个整数, 为保证最短总长度的情况下, 最长字符串 \(s_i\) 的最短长度.

Sample Input

4 2
1
1
2
2

Sample Output

12
2

Data Range

对于所有数据, 保证:\(2 \leq n \leq 10^5, 2 \leq k \leq 9\);

选手请注意使用 \(64\) 位整数进行输入输出、存储和计算.

Explanation

如果这道题想到哈夫曼树就可以了, 不然根本做不出来.

或者有类似的想法也行. 毕竟这样合并的次数最少, 代价也最小.

这让我想到了 Minecraft 的附魔机制, 最好的办法是两两附魔然后合并, 而不是线性地一股脑全部扔到附魔台上去.

具体实现方法也不是很不明确, 另外注意整除的问题.

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <queue>

using namespace std;
typedef long long lli;

struct obj { lli w; int l;
    obj(lli _, int __) { w = _, l = __; } };
bool operator < (obj a, obj b) {
    return a.w != b.w ? a.w > b.w : a.l > b.l; }

int n, k;
priority_queue<obj> pq;

int main(int argc, char** argv)
{
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) {
        lli x; scanf("%lld", &x);
        pq.push(obj(x, 1));
    }
    int m = n;
    // Maintain divisor intactness
    if ((n-1) % (k-1) > 0)
        m += (k-1) - (n-1) % (k-1);
    for (int i = n + 1; i <= m; i++)
        pq.push(obj(0, 1));
    // Emulating selection
    lli res = 0;
    while (m > 1) {
        lli s1 = 0; int s2 = 0;
        for (int i = 1; i <= k; i++) {
            obj s = pq.top(); pq.pop();
            s1 += s.w; s2 = max(s2, s.l);
        }
        res += s1; m -= k - 1;
        pq.push(obj(s1, s2 + 1));
    }
    printf("%lld\n%d\n", res, pq.top().l - 1);
    return 0;
}