题目
思路
笔者一开始是向trie树和贪心方面想,
但是经过机房巨佬的点拨,自己实际上就是写的哈夫曼树
我们实际上可以这样想,每一个单词就是一个点,点权就是它出现的次数
有一个很容易想到的贪心,点权越大的,他所拥有的长度就应该越小
我们就往这个方向去想,我们不需要知道每一个点具体编号
我们需要的只是它所出现的次数以及编号的长度
因为我们需要将最长的s的达到最短
我们其实可以将编号的过程抽象成一个个树的合并
这个树一定是k叉的
并且每一层只能有一个能往下拓展
所以我们用一个优先队列来维护每一个点的权值的大小顺序
之后取出前k个,合并之后,再塞进树里面就行了
整个过程中我们不需要建树,我们只是抽象成为一个过程而已
代码
#include<iostream>
#include<queue>
using namespace std;
struct node
{
int dep;
long long w;
friend bool operator < (const node &a,const node &b)
{
if(a.w==b.w)
return a.dep>b.dep;
return a.w>b.w;
}
}a[100005];
int n,k;
long long ans;
node cnt[15];
priority_queue<node> q;
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1;i<=n;i++)
{
long long w;
cin>>w;
q.push((node){0,w});
}
while((n-1)%(k-1))
{
n++;
q.push((node){0,1ll*0});
}
while(q.size()!=1)
{
for(int i=1;i<=k;i++)
{
cnt[i]=q.top();
q.pop();
}
node t;
t.dep=0;
t.w=0;
for(int i=1;i<=k;i++)
{
t.w+=cnt[i].w;
t.dep=max(t.dep,cnt[i].dep);
}
t.dep++;
q.push(t);
ans+=t.w;
}
cout<<ans<<' '<<q.top().dep;
return 0;
}