【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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值