1. 程式人生 > >【BZOJ4198】荷馬史詩,貪心之k叉哈夫曼樹

【BZOJ4198】荷馬史詩,貪心之k叉哈夫曼樹

傳送門
思路:
很早以前聽說過這個題
據說是一個很強的貪心(?)
然後一上來就往貪心上去想……(其實一開始知道演算法不是很好,因為你不會走彎路了)
發現這玩意好像是個合併果子的模型……
也不知道是怎麼轉化過去的,好像是什麼哈弗曼編碼,也沒有學過(pia)但是手造了幾個點,發現都是類似取最小值然後貪心合併的方法
像我這種不會擬陣啥的弱雞對付貪心就是要大膽猜想小心嘗試
那我們嘗試直接合並唄?
順便記錄個siz啥的存合併次數,在權值相同時取siz較小的不就行了嗎
這題也敢出到noi?
然後快速敲出來,交到cogs上
然後得了77分
這裡寫圖片描述
再思考:是不是取到最後可能會不足k-1個?那麼只取到剩餘k-1個,然後一口氣合併行不行?
然後得了81分
這裡寫圖片描述


這就有點蛋疼了
記得某些神犇的noi遊記裡寫這個題的時候說到了haffman樹,趕緊去學習了一個
回來之後……
原來這是個裸的k叉haffman樹啊……
原來合併果子是經典哈弗曼樹(二叉哈夫曼樹)啊……
原來這是基礎知識啊……
我以前只在初賽筆試裡見過它啊……
這裡寫圖片描述
何為弱雞
雖然這道題沒看題解,但我覺得和看題解好像沒什麼區別……啊.
程式碼:

#include<cstdio>
#include<iostream>
#include<queue>
#define LL long long
using namespace std;
int
n,k,tot,mx; LL ans; struct node{ LL val; int siz; bool operator <(const node other)const { if (val==other.val) return siz>other.siz; return val>other.val; } }a[100005]; priority_queue <node> q; main() { scanf("%d%d",&n,&k); for (int i=1
;i<=n;++i) scanf("%lld",&a[i].val), q.push(a[i]); while ((n-1)%(k-1)) ++n,q.push(a[n]); tot=n,mx=1; for (;tot>1;) { LL t1=0;int t2=0; for (int i=1;i<=k;++i,q.pop()) t1+=q.top().val, t2=max(t2,q.top().siz+1); q.push((node){t1,t2}); tot-=k-1; ans+=t1; mx=max(mx,t2); } printf("%lld\n%d\n",ans,mx); }