LOJ#2132. 「NOI2015」荷马史诗
$n \leq 100000$个数字,放进$k$叉树里,一个点只能放一个数,使所有数字乘以各自深度这个值之和最小的同时,最大深度的数字最小。
哈夫曼。这是我刚学OI那段时间看到的,感觉就是个很无聊的贪心,而且密码学我也不学深对哈夫曼的应用也了解不多,没想到出现在noi。
原来的哈夫曼只需要每次拿k个最小的数出来,建一个他们共同的父亲并在一起,当作一个权值为他们权值之和的新点,用堆可以实现;由于$(n-1) \mod (k-1)$不一定为0,需要补几个0点进去。相对于原来的哈夫曼,这里多了个深度限制,那只需要把堆里元素再记一下最大深度就可以了。
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 //#include<math.h> 5 //#include<set> 6 #include<queue> 7 //#include<bitset> 8 //#include<vector> 9 #include<algorithm> 10 #include<stdlib.h> 11 using namespace std; 12 13 #define LL long long 14 int qread() 15 { 16 char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1); 17 do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f; 18 } 19 20 //Pay attention to '-' , LL and double of qread!!!! 21 22 int n,K; 23 #define maxn 200011 24 struct qnode 25 { 26 LL v; int dep; 27 bool operator > (const qnode &b) const {return v>b.v || (v==b.v && dep>b.dep);} 28 }; 29 priority_queue<qnode,vector<qnode>,greater<qnode> > q; 30 31 int main() 32 { 33 n=qread(); K=qread(); LL v; 34 for (int i=1;i<=n;i++) {scanf("%lld",&v); q.push((qnode){v,0});} 35 if ((n-1)%(K-1)) for (int i=1,to=(K-1)-(n-1)%(K-1);i<=to;i++) q.push((qnode){0,0}),n++; 36 LL ans=0; 37 for (int i=1,to=(n-1)/(K-1);i<=to;i++) 38 { 39 LL nv=0; int nd=0; 40 for (int j=1;j<=K;j++) nv+=q.top().v,nd=max(nd,q.top().dep),q.pop(); 41 ans+=nv; q.push((qnode){nv,nd+1}); 42 } 43 printf("%lld\n%d\n",ans,q.top().dep); 44 return 0; 45 }