【BZOJ4198】荷馬史詩,貪心之k叉哈夫曼樹
阿新 • • 發佈:2019-01-30
傳送門
思路:
很早以前聽說過這個題
據說是一個很強的貪心(?)
然後一上來就往貪心上去想……(其實一開始知道演算法不是很好,因為你不會走彎路了)
發現這玩意好像是個合併果子的模型……
也不知道是怎麼轉化過去的,好像是什麼哈弗曼編碼,也沒有學過(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);
}