BZOJ4198:[NOI2015]荷马史诗
浅谈\(Huffman\)树:https://www.cnblogs.com/AKMer/p/10300870.html
题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=4198
根据题意描述,这就是要你建一棵\(k\)叉\(Huffman\)树,并且还是棵\(trie\)树。
然后记个深度,权值相同的时候选深度小的,就可以使得最长单词最短了,也就是这棵\(trie\)树会尽量扁。
时间复杂度:\(O(nlogn)\)
空间复杂度:\(O(nk)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
ll sum_len;
ll w[maxn];
int n,tot,k,mx_dep;
ll read() {
ll x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct node {
ll cnt;
int dep,id;
node() {}
node(ll _cnt,int _dep,int _id) {
cnt=_cnt,dep=_dep,id=_id;
}
bool operator<(const node &a)const {
if(cnt==a.cnt)return dep<a.dep;
return cnt<a.cnt;
}
};
struct Heap {
int tot;
node tree[maxn];
void ins(node a) {
tree[++tot]=a;
int pos=tot;
while(pos>1) {
if(tree[pos]<tree[pos>>1])
swap(tree[pos],tree[pos>>1]),pos>>=1;
else break;
}
}
node pop() {
node res=tree[1];
tree[1]=tree[tot--];
int pos=1,son=2;
while(son<=tot) {
if(son<tot&&tree[son|1]<tree[son])son|=1;
if(tree[son]<tree[pos])
swap(tree[son],tree[pos]),pos=son,son=pos<<1;
else break;
}
return res;
}
}T;
struct trie {
int son[maxn][10];
void calc_ans(int u,int dep) {
if(!son[u][0]) {
mx_dep=max(mx_dep,dep);
sum_len+=w[u]*dep;
return;
}
for(int i=0;i<k;i++)
calc_ans(son[u][i],dep+1);
}
}c;
int main() {
tot=n=read(),k=read();
for(int i=1;i<=n;i++) {
w[i]=read();
T.ins(node(w[i],1,i));
}
while((n-1)%(k-1))
tot++,n++,T.ins(node(0,1,tot));
while(T.tot!=1) {
ll tmp=0;int dep=0;++tot;
for(int i=0;i<k;i++) {
node word=T.pop();
c.son[tot][i]=word.id;
tmp+=word.cnt,dep=max(dep,word.dep);
}
T.ins(node(tmp,dep+1,tot));
}
c.calc_ans(T.tree[1].id,0);
printf("%lld\n%d\n",sum_len,mx_dep);
return 0;
}