标签:
题目背景已经暗示了这题需要用到哈夫曼编码
一句话概括(摘自百度百科):在变字长编码中,如果码字长度严格按照对应符号出现的概率大小逆序排列,则其平均码字长度为最小
所以我们从下往上构造哈夫曼树,贪心取权值最小的$k$个节点重新构造成一个节点,该点权值为这几个点的点权和,可以用$priority$_$queue$实现
为了做第二问,我们可以在优先队列里存$pair$,第一个元素是出现次数,第二个元素是最长长度,这样可以使得每次选的长度尽量小,可以得到最优解
当$k\neq 2$时,完美合并(感性理解这个词)需要满足$n\equiv 1\ (mod\ k-1)$,不满足这个条件时相当于额外添了几个出现次数为$0$的单词
所以$k\neq 2$时我们先补权值为$0$的节点使得可以完美合并,之后贪心即可
1 #include <bits/stdc++.h> 2 #define fir first 3 #define sec second 4 using namespace std; 5 typedef long long ll; 6 typedef pair<ll, ll> pll; 7 priority_queue<pll, vector<pll>, greater<pll> > PQ; 8 int main() 9 { 10 int n, k; 11 pll x, y, ans; 12 cin >> n >> k; 13 for(int i = 1; i <= n; ++i) 14 { 15 cin >> x.first; 16 PQ.push(x); 17 } 18 while(k > 2 && n % (k - 1) != 1) 19 PQ.push(y), ++n; 20 while(PQ.size() != 1) 21 { 22 y.fir = y.sec = 0; 23 for(int i = 1; i <= k; ++i) 24 { 25 x = PQ.top(), PQ.pop(); 26 y.fir += x.fir; 27 y.sec = max(y.sec, x.sec + 1); 28 } 29 ans.fir += y.fir; 30 ans.sec = max(ans.sec, y.sec); 31 PQ.push(y); 32 } 33 cout << ans.fir << endl << ans.sec << endl; 34 return 0; 35 }
[BZOJ4198] [Noi2015] 荷马史诗 (贪心)
标签:
原文地址:http://www.cnblogs.com/CtrlCV/p/5619680.html