[BZOJ]4198 [NOI2015] 荷馬史詩 哈夫曼樹

4198: [Noi2015]荷馬史詩

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 1512  Solved: 797
[Submit][Status][Discuss]

Description

追逐影子的人,自己就是影子。 ——荷馬

Allison 最近迷上了文學。她喜歡在一個慵懶的午後,細細地品上一杯卡布奇諾,靜靜地閱讀她愛不釋手的《荷馬史詩》。但是由《奧德賽》和《伊利亞特》組成的鴻篇鉅製《荷馬史詩》實在是太長了,Allison 想通過一種編碼方式使得它變得短一些。
一部《荷馬史詩》中有 n 種不同的單詞,從 1 到 n 進行編號。其中第 i 種單詞出現的總次數爲 wi。Allison 想要用 k 進制串 si 來替換第 i 種單詞,使得其滿足如下要求:
對於任意的 1≤i,j≤n,i≠j,都有:si 不是 sj 的前綴。
現在 Allison 想要知道,如何選擇 si,才能使替換以後得到的新的《荷馬史詩》長度最小。在確保總長度最小的情況下,Allison 還想知道最長的 si 的最短長度是多少?
一個字符串被稱爲 k 進制字符串,當且僅當它的每個字符是 0 到 k−1 之間(包括 0 和 k−1)的整數。
字符串 Str1 被稱爲字符串 Str2 的前綴,當且僅當:存在 1≤t≤m,使得 Str1=Str2[1..t]。其中,m 是字符串 Str2 的長度,Str2[1..t] 表示 Str2 的前 t 個字符組成的字符串。

Input

輸入文件的第 1 行包含 2 個正整數 n,k,中間用單個空格隔開,表示共有 n 種單詞,需要使用 k 進制字符串進行替換。

接下來 n 行,第 i+1 行包含 1 個非負整數 wi,表示第 i 種單詞的出現次數。

Output

輸出文件包括 2 行。

第 1 行輸出 1 個整數,爲《荷馬史詩》經過重新編碼以後的最短長度。
第 2 行輸出 1 個整數,爲保證最短總長度的情況下,最長字符串 si 的最短長度。

Sample Input

4 2
1
1
2
2

Sample Output

12
2

HINT

用 X(k) 表示 X 是以 k 進製表示的字符串。

一種最優方案:令 00(2) 替換第 1 種單詞,01(2) 替換第 2 種單詞,10(2) 替換第 3 種單詞,11(2) 替換第 4 種單詞。在這種方案下,編碼以後的最短長度爲:


1×2+1×2+2×2+2×2=12

最長字符串 si 的長度爲 2。


一種非最優方案:令 000(2) 替換第 1 種單詞,001(2) 替換第 2 種單詞,01(2) 替換第 3 種單詞,1(2) 替換第 4 種單詞。在這種方案下,編碼以後的最短長度爲:


1×3+1×3+2×2+2×1=12

最長字符串 si 的長度爲 3。與最優方案相比,文章的長度相同,但是最長字符串的長度更長一些。


對於所有數據,保證 2≤n≤100000,2≤k≤9。


選手請注意使用 64 位整數進行輸入輸出、存儲和計算。


Source

[Submit][Status][Discuss]


HOME Back

  學習了一發哈夫曼樹... 於是就來看這道當時讓很多神犇跪倒的題目... 怎麼會考到這麼偏的東西? 不會就跪啊.  看了之後再來看這道題? ??? k進制所以是k叉哈夫曼? 長度最小同時最長也要最小隻要在建樹過程中貪心一下就行了. 權值相同要深度最小的. 注意不滿k叉要補0點.

  爲什麼priority_queue的排序重載方式要反過來? 調了半天. (主要是我弱)

#include<bits/stdc++.h>
using namespace std;
typedef long long lnt;
lnt ans;
int n, res, k;
struct node {
	lnt val; int dep;
	inline friend bool operator < (const node &a ,const node &b) {
		return (a.val == b.val) ? a.dep > b.dep : a.val > b.val;
	}
};
priority_queue<node> q;
inline const lnt read() {
	register lnt x = 0;
	register char ch = getchar();
	while (ch < '0' || ch > '9') ch = getchar();
	while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
	return x;
}
int main() {
	n = read(), k = read();
	register lnt x;
	register int i, res;
	for (i = 1; i <= n; ++ i)
		x = read(), q.push((node){x, 1}); 
	res = (n - 1) % (k - 1);
	if (res) res = k - 1 - res, n += res;
	for (i = 1; i <= res; ++ i) q.push((node){0, 1});
	while (n > 1) {
		int mxd = 0;
		lnt mxv = 0;
		for (i = 1; i <= k; ++ i) {
			mxv += q.top().val;
			mxd = max(mxd, q.top().dep);
			q.pop();
		}
		n -= k - 1;
		ans += mxv;
		q.push((node){mxv, mxd + 1});
	}
	printf("%lld\n%d", ans, q.top().dep - 1);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章