【Huffman树】【贪心】【NOI 2015】【bzoj 4198】荷马史诗

4198: [Noi2015]荷马史诗Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 127 Solved: 80

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 到 k1 之间(包括 0 和 k1)的整数。

字符串 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 21122

Sample Output

122

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 位整数进行输入输出、存储和计算。

题解:

如果没有想到Huffman就跪了。。 分析题目,发现出现次数其实就是权重,我们要求的就是一种编码方案使得权重×编码长和最小,可以直接套k叉Huffman树乱搞。 类比合并果子,考虑倒着进行编码。从叶子节点开始编码,每次取出最小k个数合成一个x,然后编码长加1(实际上是倒着的,但其实是一样的),再把x扔回去,以此类推。 注意: 可能会有空节点,即可能存在一个节点儿子不足k个,这就需要补零以防出错,常用的判断方法:(n-1)%(k-1),等于0代表是满k叉树。 (因为对于一棵满k叉树,任意节点要么有k个儿子,要么没有儿子,设叶子节点有x个,则(n-x)*k=n-1,推导一下即可)

Code:

;#define LL long longstruct H{LL w; int l;bool operator < (const H &a) const {if (w!=a.w) return a.w<w;return a.l<l;}};priority_queue<H> h;int n,k,nn; LL ans=0;int in(){int x=0; char ch=getchar();while (ch<‘0′ || ch>’9′) ch=getchar();while (ch>=’0′ && ch<=’9’) x=x*10+ch-‘0’,ch=getchar();return x;}LL Lin(){LL x=0; char ch=getchar();while (ch<‘0′ || ch>’9′) ch=getchar();while (ch>=’0′ && ch<=’9’) x=x*10+(LL)(ch-‘0’),ch=getchar();return x;}int main(){n=in(),k=in(); nn=n;for (int i=1; i<=n; i++){LL x=Lin();h.push((H){x,1});}if ((n-1)%(k-1)) nn+=(k-1)-((n-1)%(k-1));for (int i=n+1; i<=nn; i++)h.push((H){0,1});while (nn>1){LL s1=0; int s2=0;for (int i=1; i<=k; i++){H x=h.top(); h.pop();s1+=x.w; s2=max(s2,x.l);}ans+=s1; nn-=(k-1);h.push((H){s1,s2+1});}printf(“%lld\n%d\n”,ans,h.top().l-1);return 0;}

今天不想走,明天就要跑了。

【Huffman树】【贪心】【NOI 2015】【bzoj 4198】荷马史诗

相关文章:

你感兴趣的文章:

标签云: