4198: [Noi2015]荷马史诗
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2200 Solved: 1169
[ Submit][ Status][ Discuss]
Description
追逐影子的人,自己就是影子。 ——荷马
Input
输入文件的第 1 行包含 2 个正整数 n,k,中间用单个空格隔开,表示共有 n 种单词,需要使用 k 进制字符串进行替换。
Output
输出文件包括 2 行。
题解:
huffman树相关知识:
1.带权路径长度:$W_{PL} = \sum_{i=1}^{n} w_{i} l_{i}$ 其中$w_{i}$为每个叶子结点的权值,$l_{i}$为每个叶子结点到根的路径长度;
Huffman即WPL最小的二叉树;
每次选权值最小的两个点合并并加入一个权值为两个点权值和的新点;
直到只有一个点;(我太弱了所以还没有YY出证明,改天翻wiki吧)
满足WPL最小;
应用:huffman编码:
实际上huffman是为了解决:对字符串加密成二进制串,给出字符串中每个字符出现的次数,由于不能造成歧义所以必须要满足任何一个字符的二进制编码都不是另一个不同字符的二进制编码的前缀,使得整个加密后的二进制串长度最小;
完整的huffman就在上面建出来的树的边加上0 1 ,即变成一个字典树,每个点对应的二进制串即编码
回到原题
所以出题人就是想出个huffman树 , 只不过是k叉的;
最长字符串长度最短不是问题,优先队列实现的时候第二关键字为当前根最大深度即可;
k叉有点坑,需要补上(n - n%(k-1)) %(k-1)个权值为0的点;
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define mk make_pair 4 #define fir first 5 #define sec second 6 using namespace std; 7 const int N=100010; 8 int n,k; 9 typedef pair<ll,ll> pii; 10 priority_queue<pii,vector<pii>,greater<pii> >q; 11 int main(){ 12 // freopen("bzoj4198.in","r",stdin); 13 // freopen("bzoj4198.out","w",stdout); 14 scanf("%d%d",&n,&k); 15 for(int i=1;i<=n;i++){ 16 ll x;scanf("%lld",&x); 17 q.push(mk(x,0)); 18 } 19 int lim=(k-1-(n-1)%(k-1))%(k-1); 20 for(int i=1;i<=lim;i++)q.push(mk(0,0)); 21 ll ansx=0,ansy=0; 22 while(!q.empty()){ 23 ll x=0,y=0; 24 for(int i=1;i<=k&&!q.empty();i++,q.pop()){ 25 pii u=q.top(); 26 x+=u.fir; 27 y=max(y,u.sec); 28 } 29 y++; 30 ansx+=x,ansy=max(ansy,y); 31 if(q.empty())break; 32 q.push(mk(x,y)); 33 } 34 printf("%lld\n%lld\n",ansx,ansy); 35 return 0; 36 } 37 38