看到这个题一脸懵逼啊?难道是字符串??
结果一看题解,是什么哈夫曼树(不会啊)
这里留个坑···还没有十分了解哈夫曼树是啥
但是看样子好像就是一棵二叉树,每次将权值小的合并成新的点
新点权值是原来的和
这个背景好像很裸???
Huffman树之所以可以保证合法性,是因为加入了许多虚拟结点,保证了一定不会有一个是另一个前缀的情况,考虑一个结点到根结点的路径上的所有点一定都是虚拟结点,所以很容易确定构造方法的合法。
求第二问的时候我们可以合并的时候优先合并深度较小的
这样就能保证整个树的最大深度最小了(为什么yy一下!)
当k≠2时,完美合并(感性理解这个词)需要满足n≡1 (mod k−1),不满足这个条件时相当于额外添了几个出现次数为0的单词
所以k≠2时我们先补权值为0的节点使得可以完美合并,之后贪心即可
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#define maxn 100005
#define LL long long
using namespace std;
int n,k,ans2;
LL ans1;
inline LL rd(){
LL x=0,f=1;char c=' ';
while(c<'0' || c>'9') {if(c=='-')f=-1;c=getchar();}
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
struct node{
LL val; int dep;
inline bool operator <(const node &x) const {
return val>x.val||(val==x.val&&dep>x.dep);
}
}tmp;
priority_queue<node> q;
int main(){
scanf("%d%d",&n,&k); LL x;
for(int i=1;i<=n;i++){
x=rd(); q.push((node){x,1});
}
int rm=(n-1)%(k-1);
if(rm) rm=k-1-rm,n+=rm;
for(int i=1;i<=rm;i++) q.push((node){0,1});//用0来补齐
while(n>1){
int maxd=0; LL tot=0;
for(int i=1;i<=k;i++){
tmp=q.top(); q.pop();
tot+=tmp.val;
maxd=max(maxd,tmp.dep);
}
q.push((node){tot,maxd+1});//从下往上建树
ans1+=tot; ans2=max(ans2,maxd);
n-=k-1;
}
printf("%lld\n%d\n",ans1,ans2);
}