• 【NOI2015】荷马史诗


    显然一个Huffman树,然后改成 (K) 叉的就好。但是我不会Huffman树,于是学学拓宽知识面。

    首先这个 (K) 叉树就是一个类似字典树的东西,但是不对应目标串的点都是非叶结点(不然不满足前缀关系的限制)

    容易证明,每个点带 (K - 1) 个叶子是最优的。

    考虑计算总权值时的 深度乘以权值 改为 它到根的链上都加上它的权值,那么 (sum dep_i imes val_i = sum_{u otin leaves} v_i)

    于是让权值大的尽量贡献最少,那么就要出现在深度浅的地方。

    因此考虑自底向上构建。考虑维护一个堆,每次取出前 (K) 小的,合并成一个点,然后扔进堆里。合并的时候维护权值(子节点的和)。直到合并成单个点。显然,权值越大的贡献次数越小。于是这样贪心是正确的(然而我并不会严格的证明)。

    然后就建出一个 Huffman树了。但是对于第二问我们还是要得出深度最小值,于是加入第二关键字深度,合并的时候注意维护就行了。

    还有因为每次减少 (K - 1) 个,所以可能最后剩下不是 (1) 个,所以,补上几个 (0) 使得 (n equiv 1 (mod K - 1)),显然不会对答案产生影响。

    我挂在了补 (0) 以及 第二关键字上,WA了两发。

    #include <bits/stdc++.h>
    
    typedef long long LL;
    typedef std::pair<LL, int> P;
    std::priority_queue<P, std::vector<P>, std::greater<P> > q;
    int n, K; LL t;
    int main() {
    	std::ios_base::sync_with_stdio(false), std::cin.tie(0);
    	std::cin >> n >> K;
    	for (int i = 1; i <= n; ++i) std::cin >> t, q.emplace(t, 0);
    	while (n % (K - 1) != 1 % (K - 1)) ++n, q.emplace(0, 0);
    	LL ans = 0;
    	while (q.size() != 1) {
    		LL tv = 0; int dx = 0;
    		for (int i = 1; i <= K; ++i)
    			tv += q.top().first, dx = std::max(dx, q.top().second), q.pop();
    		q.emplace(tv, dx + 1); ans += tv;
    	}
    	std::cout << ans << std::endl << q.top().second << std::endl;
    	return 0;
    }
    
  • 相关阅读:
    SSH 免密登录配置
    Hadoop 2.7.2 集群安装配置
    将oracle数据库中数据写入excel文件
    PLSQL提交请求集
    oracle会计工作总结,EBS 创建会计科目 小结
    将oracle数据库中数据写入excel文件
    如何成为一名优秀的工程师(听讲座有感) Winema
    基于W5300的嵌入式以太网接口设计 Winema
    Java 基础入门随笔(2) JavaSE版——关键字、进制转换、类型转换
    VMware 11安装Mac OS X 10.10 及安装Mac Vmware Tools.
  • 原文地址:https://www.cnblogs.com/daklqw/p/11587281.html
Copyright © 2020-2023  润新知