题目大意:一篇文章有n个单词,其中第i个单词的出现次数为w[i]。你要用k进制串s[i]替换第i种单词。要求:对于任意i!=j,都有s[i]不是s[j]的前缀。
要使替换后的文章总长度最小。
求这个最小总长度。
在这个前提下,要使s[i]的最大长度最短,求这个最短的长度
题解:k叉哈夫曼树
取最小的k个合并即可
发现只有当(n-1)%(k-1)=0的时候才能恰好合并,所以要添加k-1-(n-1)%(k-1)个权值为0高度为1的虚拟节点
用堆维护就好了
为了保证最大高度最小,把高度加成第二关键字
我的收获:姿势++
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n,k,ans;
struct node{
ll val,dep;
node(){}
node(ll _,ll __){val=_,dep=__;}
}tmp;
bool operator <(node x,node y){return x.val>y.val||(x.val==y.val&&x.dep>y.dep);}
priority_queue<node> q;
ll readin()
{
ll x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+(ll)(ch-'0'),ch=getchar();
return x;
}
void work()
{
while(n>1){
ll maxd=0,tot=0;
for(ll i=1;i<=k;i++){
tmp=q.top();q.pop();
tot+=tmp.val;
maxd=max(maxd,tmp.dep);
}
q.push(node(tot,maxd+1));
ans+=tot;n-=k-1;
}
printf("%lld\n%lld\n",ans,q.top().dep-1);
}
void init()
{
n=readin();k=readin();
for(ll i=1;i<=n;i++) q.push(node(readin(),1));
ll remain=(n-1)%(k-1);
if(remain!=0) remain=k-1-remain,n+=remain;
for(ll i=1;i<=remain;i++) q.push(node(0,1));
}
int main()
{
init();
work();
return 0;
}