zoukankan      html  css  js  c++  java
  • 【bzoj4198】 Noi2015—荷马史诗

    http://www.lydsy.com/JudgeOnline/problem.php?id=4198 (题目链接)

    题意

      一篇文章n个单词,每个出现了${w_i}$次,用k进制数代替单词,使得任意单词不是另一个单词的前缀。如何选择使文章的总长度最小,且在总长度最小情况下最长的k进制数的长度最小是多少

    Solution

      LCF不写博客→_→,我只好自己写了。。

      将每个单词看成权值为${w_i}$的节点,很显然是个k叉哈弗曼树,考虑k=2的情况,就是一个“合并果子”。但是对于一般情况如果我们用用合并果子的做法会Wa,因为可能第一层的节点并没有满,那么如果把某一个叶子节点放到第一层一定会更优。所以我们加节点,其权值为0,直到${(k-1)|(n-1)}$,也就是说合并到最后一步一定正好剩下n个节点。

      考虑第二问,我们在堆中添加第二关键字,就是当前最深节点的深度。于是问题就解决了。

    细节

      开LL,堆里面也要开→_→

    代码

    // bzoj4198
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define inf 1<<30
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=100010;
    int n,K;
    
    struct data {
    	LL w;int d;
    	friend bool operator < (const data a,const data b) {
    		return a.w==b.w ? a.d>b.d : a.w>b.w;
    	}
    };
    int main() {
    	scanf("%d%d",&n,&K);
    	priority_queue<data> q;
    	LL ans=0;
    	for (int i=1;i<=n;i++) {
    		LL x;scanf("%lld",&x);
    		q.push((data){x,0});
    	}
    	while ((n-1)%(K-1)) n++,q.push((data){0,0});
    	while (q.size()>1) {
    		LL w=0;int d=0;
    		for (int i=1;i<=K;i++) {w+=q.top().w,d=max(d,q.top().d);q.pop();}
    		ans+=w;
    		q.push((data){w,d+1});
    	}
    	printf("%lld
    %d",ans,q.top().d);
        return 0;
    }
    
  • 相关阅读:
    Ubuntu下访问Windows中Postgresql
    Ubuntu下访问Windows中Postgresql
    “大家好,我是渣渣辉”这款油腻游戏的背后是90后老板和10亿现金流
    ID 选择器
    getElementById
    遇见未来 | 超融合如何兼顾企业的“敏态”和“稳态”的业务需求
    赏完超级蓝血月,再来品味这10个与月亮有关的创业项目
    CSS选择器
    jquery dom操作
    getElementById
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6278790.html
Copyright © 2011-2022 走看看