传送门
思路:
很早以前听说过这个题
据说是一个很强的贪心(?)
然后一上来就往贪心上去想……(其实一开始知道算法不是很好,因为你不会走弯路了)
发现这玩意好像是个合并果子的模型……
也不知道是怎么转化过去的,好像是什么哈弗曼编码,也没有学过(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);
}