P2168 [NOI2015] 荷马史诗 - 哈夫曼树
题解
其实就是构造一个 \(k\) 叉哈夫曼树,并在保证 \(\sum w_i\times dep_i\) 最小的情况下使得树的深度最小。
由于哈夫曼树自下而上构造时,可能出现最顶层不满 \(k\) 个的情况,所以如果 \((n-1)\bmod (k-1)\neq 0\),需要补 \(k-1-((n-1)\bmod (k-1))\) 个虚点,使得最底层而不是最顶层不满 \(k\) 个。
代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <utility>
#include <queue>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
template<typename T> void Read(T &_x){
_x=0;int _f=1;
char ch=getchar();
while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();
while(isdigit(ch)) _x=_x*10+(ch^48),ch=getchar();
_x*=_f;
}
template<typename T,typename... Args> void Read(T &_x,Args& ...others){
Read(_x);Read(others...);
}
typedef long long ll;
typedef pair<ll,int> pii;
const int N=1e5+5;
int n,k;ll w[N];
priority_queue<pii,vector<pii>,greater<pii>> q;
int main(){
Read(n,k);
For(i,1,n){
Read(w[i]);q.push({w[i],0});
}
int cnt=(n-1)%(k-1)?k-1-(n-1)%(k-1):0;
For(i,1,cnt) q.push({0,0});
ll ans=0;
while(q.size()>1){
ll w=0,h=0;
For(i,1,k){
pii x=q.top();q.pop();
w+=x.first,h=max(h,ll(x.second));
}
ans+=w,q.push({w,h+1});
}
printf("%lld\n%d\n",ans,q.top().second);
return 0;
}
Written by Alan_Zhao