zoukankan      html  css  js  c++  java
  • P2168 [NOI2015]荷马史诗

    P2168 [NOI2015]荷马史诗

    题目描述

    追逐荷马的人,自己就是影子 ——荷马

    追逐影子的人,自己就是荷马 ——影子

    追逐荷马的人,自己就是荷马 ——影子

    追逐影子的人,自己就是影子 ——荷马

    Allison 最近迷上了文学。她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的《荷马史诗》。但是由《奥德赛》和《伊利亚特》 组成的鸿篇巨制《荷马史诗》实在是太长了,Allison 想通过一种编码方式使得它变得短一些。

    一部《荷马史诗》中有n种不同的单词,从1到n进行编号。其中第i种单 词出现的总次数为wi。Allison 想要用k进制串si来替换第i种单词,使得其满足如下要求:

    对于任意的 1 ≤ i, j ≤ n , i ≠ j ,都有:si不是sj的前缀。

    现在 Allison 想要知道,如何选择si,才能使替换以后得到的新的《荷马史诗》长度最小。在确保总长度最小的情况下,Allison 还想知道最长的si的最短长度是多少?

    一个字符串被称为k进制字符串,当且仅当它的每个字符是 0 到 k − 1 之间(包括 0 和 k − 1 )的整数。

    字符串 str1 被称为字符串 str2 的前缀,当且仅当:存在 1 ≤ t ≤ m ,使得str1 = str2[1..t]。其中,m是字符串str2的长度,str2[1..t] 表示str2的前t个字符组成的字符串。

    输入输出格式

    输入格式:

    输入的第 1 行包含 2 个正整数 n, k ,中间用单个空格隔开,表示共有 n种单词,需要使用k进制字符串进行替换。

    接下来n行,第 i + 1 行包含 1 个非负整数wi ,表示第 i 种单词的出现次数。

    输出格式:

    输出包括 2 行。

    第 1 行输出 1 个整数,为《荷马史诗》经过重新编码以后的最短长度。

    第 2 行输出 1 个整数,为保证最短总长度的情况下,最长字符串 si 的最短长度。

    输入输出样例

    输入样例#1: 
    4 2
    1
    1
    2
    2
    
    输出样例#1: 
    12
    2
    输入样例#2: 
    6 3
    1
    1
    3
    3
    9
    9
    
    输出样例#2: 
    36
    3
    

    说明

    【样例说明 1】

    用 X(k) 表示 X 是以 k 进制表示的字符串。

    一种最优方案:令 00(2) 替换第 1 种单词, 01(2) 替换第 2 种单词, 10(2) 替换第 3 种单词,11(2) 替换第 4 种单词。在这种方案下,编码以后的最短长度为:

    1 × 2 + 1 × 2 + 2 × 2 + 2 × 2 = 12

    最长字符串si的长度为 2 。

    一种非最优方案:令 000(2) 替换第 1 种单词,001(2) 替换第 2 种单词,01(2)替换第 3 种单词,1(2) 替换第 4 种单词。在这种方案下,编码以后的最短长度为:

    1 × 3 + 1 × 3 + 2 × 2 + 2 × 1 = 12

    最长字符串 si 的长度为 3 。与最优方案相比,文章的长度相同,但是最长字符串的长度更长一些。

    【样例说明 2】

    一种最优方案:令 000(3) 替换第 1 种单词,001(3) 替换第 2 种单词,01(3) 替换第 3 种单词, 02(3) 替换第 4 种单词, 1(3) 替换第 5 种单词, 2(3) 替换第 6 种单词。

    【提示】

    选手请注意使用 64 位整数进行输入输出、存储和计算。

    【时限1s,内存512M】

    ——————————————————————————————————————————————————————————————————

     第一眼看到这题

    啥啊

    思考若干分钟后……看题解

    Huffman树Hufman编码都是啥啊

    真神奇

     题解链接

    code

    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <iostream>
    #include <map>
    #include <queue>
    #define R register
    #define mp(x, y) std::make_pair(x, y)
    
    typedef long long ll;
    typedef double db;
    typedef std::pair<ll, ll> pir;
     
    int n, k;
    ll cnt, ans, mh, t;
    
    std::priority_queue<pir, std::vector<pir >, std::greater<pir > >pq;
    
    template <typename T> inline T read(T &x) {
        char ch = getchar(), f = 0; x = 0;
        while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();} 
        while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
        if(f) x = -x; return x;
    }
    
    int main() {
        read(n); read(k); ll t;
        for (R int i = 1; i <= n; ++ i) {
            //初始化Huffman树,建立t个高度为1的叶子节点
            read(t);
            pq.push(mp(t, 1));
        }
        //Huffman树与其他树构造方法不同,是从下至上构造
        //Huffman树不是满二叉树,如果不补全会出现靠近根结点的位置反而会空,得不到最优解
        //加入空节点使之成为满二叉树,将非空节点向上挤到更优位置
        if ((n - 1) % (k - 1)) cnt = k - 1 - (n - 1) % (k - 1);
        for (R int i = 1; i <= cnt; ++ i) 
            pq.push(mp(0, 1));
        //一共有n个节点要合并
        cnt += n;
        while (cnt > 1) {
            //将k个节点合并成一个节点
            t = mh = 0; pir h;
            for (R int i = 1; i <= k; ++ i) {
                h = pq.top();
                t += h.first;
                mh = std::max(mh, h.second);
                pq.pop();
            }
            //Huffman树保证了最短带权路径
            ans += t;
            //合并后的节点在合并前节点之上
            pq.push(mp(t, mh + 1));
            cnt -= k - 1;
        }
        std::cout << ans << std::endl;
        std::cout << pq.top().second - 1 << std::endl;
        return 0;
    }
  • 相关阅读:
    深入理解计算机系统 第六章 存储器层次结构 第二遍
    深入理解计算机系统 第六章 存储器层次结构
    深入理解计算机系统 第八章 异常控制流 Part2 第二遍
    深入理解计算机系统 第八章 异常控制流 part2
    深入理解计算机系统 第八章 异常控制流 Part1 第二遍
    深入理解计算机系统 第八章 异常控制流 part1
    深入理解计算机系统 第三章 程序的机器级表示 Part2 第二遍
    深入理解计算机系统 第三章 程序的机器级表示 part2
    深入理解计算机系统 第三章 程序的机器级表示 Part1 第二遍
    深入理解计算机系统 第三章 程序的机器级表示 part1
  • 原文地址:https://www.cnblogs.com/hkttg/p/9424698.html
Copyright © 2011-2022 走看看