• 【贪心 哈夫曼树】bzoj2923: [Poi1998]The lightest language


    失去了以前用STL乱搞的能力……

    题目描述

    语言也是数学上经常研究的一种数据。

    给出数学上关于语言的如下定义:

    • 字母表:大小为 K 的字母表是一个由 K 不同的字符组成的集合。
    • 单词:长度为 m 的单词是以 m 个字母表中的字符组成的字符串。
    • 语言:语言是由若干个单词组成的集合。
    • 非前缀的:一种语言是非前缀的,当且仅当其中任意两个单词不存在前缀关系。

    现在每个字母表中的字母有一个权值,单词的权值是单词中每个字母的权值和,语言的权值是单词的权值之和。

    例如:

    K=2,字母a权值为 2,字母b权值为 5,字符串aba权值为 9。

    语言 {ab,aba,b不是非前缀的,而非前缀的语言 {aa,ab,b} 权值是 16

    给出n,K,每个字母的权值 Wi,求包含 n 个单词的非前缀语言中最小的权值是多少。

    数据范围

    对于 20% 的数据,n,K5

    对于另 30% 的数据,wi=1

    对于另 30% 的数据,K=2

    对于所有数据,2n10000,2K26,1wi10000

    时间限制 1s

    空间限制 256 MB


    题目分析

    整个单词树可以看做trie的样子,

    那么我的第一思路就是在这个tire上面树形dp……

    既然要dp那么肯定要涉及到开数组空间的问题。

    注意到若一层能够“铺满”所有n个节点,那么往下编码是一定不更优的。所以最大情况是补成一个满二叉树。

    但是这个数据范围对于树上背包来说不对啊……

    于是就活生生卡住一个小时。

    回过头来看这个问题:非前缀;最小编码和……

    这是个类哈夫曼树的问题啊。

    与常规的哈夫曼问题不同,此题既然确定个数而加权不同,就可以从树根往下处理。

    于是乎,这么一个贪心扩展的过程,就可以用multiset来维护……

    最后STL的细节问题需要注意一下。

     1 #include<bits/stdc++.h>
     2 typedef long long ll;
     3 const int maxn = 10035;
     4 
     5 ll sum,ans;
     6 int n,k,w[maxn];
     7 std::multiset<ll> s;
     8 
     9 int read()
    10 {
    11     char ch = getchar();
    12     int num = 0;
    13     bool fl = 0;
    14     for (; !isdigit(ch); ch = getchar())
    15         if (ch=='-') fl = 1;
    16     for (; isdigit(ch); ch = getchar())
    17         num = (num<<1)+(num<<3)+ch-48;
    18     if (fl) num = -num;
    19     return num;
    20 }
    21 int main()
    22 {
    23     n = read(), k = read(), ans = 1ll<<40;
    24     for (int i=1; i<=k; i++)
    25         w[i] = read(), sum += w[i], s.insert(w[i]);
    26     for (ll cnt=sum; cnt<ans;)
    27     {
    28         if (s.size()==n){
    29             if (cnt < ans) ans = cnt;
    30             else break;
    31         }
    32         std::multiset<ll>::iterator p = s.begin();
    33         cnt += sum+(*p)*k;
    34         for (int i=1; i<=k; i++)
    35             s.insert(w[i]+*p);
    36         cnt -= *p, s.erase(p);
    37         while (s.size() > n)
    38             cnt -= *s.rbegin(), s.erase(--s.end());
    39     }
    40     printf("%lld
    ",ans);
    41     return 0;
    42 }

    END

  • 相关阅读:
    elasticsearch配置文件
    elk+filebeat源码安装
    logstash配置文件
    kibana配置文件
    filebeat配置文件
    老年人和棒子(李敖)
    Linux下傻瓜式安装配置V_2_r_a_y
    【有关学习Q国的自动化工具的学习思路】
    有关在使用aireplay-ng处理5Ghz频段的wifi时出现“No such Bssid available”的解决方法
    springboot整合日志logback
  • 原文地址:https://www.cnblogs.com/antiquality/p/9656035.html
Copyright © 2020-2023  润新知