学了哈夫曼树这道题还是好想的,基本上和构造哈夫曼树的思路一样,但是题目要求最长si的最小值,所以用两个关键字的堆,第一关键字是把出现次数作为权值,第二关键字表示从该节点开始的最长长度,权值相同时,选择长度较小的合并。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 struct node{ 5 ll num,dep; 6 //node(){} 7 node(ll a,ll b){num=a,dep=b;} 8 bool operator < (const node &a) const { 9 if(num==a.num) return a.dep<dep; 10 else return a.num<num; 11 } 12 }; 13 14 priority_queue<node> q; 15 ll k,n,ans,cnt; 16 17 int main(){ 18 scanf("%lld%lld",&n,&k); 19 for(int i=1;(ll)i<=n;i++){ 20 ll temp; 21 scanf("%lld",&temp); 22 q.push(node(temp,0));//将出现的次数都当做权值,做哈夫曼 23 } 24 cnt=n; 25 if((n-1)%(k-1)) cnt+=(k-1-(n-1)%(k-1));//补点 26 for(int i=n+1;(ll)i<=cnt;i++) 27 q.push(node(0,0));//插入新补的点 28 while(cnt>1){ 29 ll sum=0,len=0; 30 for(int i=1;(ll)i<=k;i++){ 31 sum+=q.top().num; 32 len=max(len,q.top().dep); 33 q.pop(); 34 } 35 q.push(node(sum,len+1)); 36 cnt=cnt-k+1; 37 ans+=sum; 38 } 39 printf("%lld\n",ans); 40 printf("%lld\n",q.top().dep); 41 }