zoukankan      html  css  js  c++  java
  • 【BZOJ4198】[Noi2015]荷马史诗 贪心+堆

    【BZOJ4198】[Noi2015]荷马史诗

    Description

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

    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 个字符组成的字符串。

    Input

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

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

    Output

    输出文件包括 2 行。

    第 1 行输出 1 个整数,为《荷马史诗》经过重新编码以后的最短长度。
    第 2 行输出 1 个整数,为保证最短总长度的情况下,最长字符串 si 的最短长度。

    Sample Input

    4 2
    1
    1
    2
    2

    Sample Output

    12
    2

    HINT

    用 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≤n≤100000,2≤k≤9。
    选手请注意使用 64 位整数进行输入输出、存储和计算。

    题解:好吧我这个蒟蒻不会哈夫曼树,不会哈夫曼编码,我只会合并果子~

    一开始,我们认为原来有n堆数,每堆数都有权值,将他们扔到优先队列里,每次取出权值和最小的k堆,将他们合成一堆。再扔回到优先队列里去。但是此题还要求最长单词的长度最小,我们就给每堆数维护一个pair,代表它的(权值和)以及(最多的合并次数)。

    由于每次取出k个,扔回去一个,最终剩1个,所以要满足n%(k-1)=1(当k不等于2时),所以如果n%(k-1)不等于1时我们要向堆里扔一些权值为0的数补齐。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <utility>
    #define mp(A,B)	make_pair(A,B)
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> pll;
    priority_queue<pll> pq;
    ll n,k;
    pll x,y,ans;
    int main()
    {
    	scanf("%lld%lld",&n,&k);
    	ll i,a;
    	for(i=1;i<=n;i++)	scanf("%lld",&a),pq.push(mp(-a,0));
    	while(k!=2&&n%(k-1)!=1)	pq.push(mp(0,0)),n++;
    	while(pq.size()!=1)
    	{
    		x=y=mp(0,0);
    		for(i=1;i<=k;i++)
    		{
    			y=pq.top(),pq.pop();
    			x.first+=y.first,x.second=min(x.second,y.second-1);
    		}
    		ans.first-=x.first,ans.second=max(ans.second,-x.second),pq.push(x);
    	}
    	printf("%lld
    %lld",ans.first,ans.second);
    	return 0;
    }
  • 相关阅读:
    HDU 5492 Find a path
    codeforce gym 100548H The Problem to Make You Happy
    Topcoder SRM 144 Lottery
    codeforce 165E Compatible Numbers
    codeforce gym 100307H Hack Protection
    区间DP总结
    UESTC 1321 柱爷的恋爱 (区间DP)
    HDU 4283 You Are the One (区间DP)
    HDU 2476 String painter (区间DP)
    UESTC 426 Food Delivery (区间DP)
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7124607.html
Copyright © 2011-2022 走看看