UOJ#130 荷马史诗

来源:互联网 发布:吉野家 知乎 编辑:程序博客网 时间:2024/06/11 16:59

题目背景

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

题目

Alcohol_C(哎嘿嘿,高大上的我给题目的主人公改了个名字)最近迷上了文学。他喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地读他爱不释手的《荷马史诗》。但是由于《奥德赛》和《伊利兰特》组成的鸿篇巨制《荷马史诗》实在是太长了,Alcohol_C想让它变得更短一些。

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

对于任意的1i,jn,ij,都有:si 不是 sj 的前缀。

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

一个字符串被成为 k 进制串,当且仅当它的每一个字符都是 0k1 (包括 0k1 ) 的整数。

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

输入格式

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

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

输出格式

输出文件包含两行。

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

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

样例一

Input

4 21122

Output

122

Explanation

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

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

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

最长字符串 sisi 的长度为 22。

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

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

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

样例二

Input

6 3113399

Output

363

Explanation

一种最优方案:令 000(3)000(3) 替换第 11 种单词,001(3)001(3) 替换第 22 种单词,01(3)01(3) 替换第 33 种单词,02(3)02(3) 替换第 44 种单词,1(3)1(3) 替换第 55 种单词,2(3)2(3) 替换第 66 种单词。

数据范围

对于所有数据,保证 2n1000002k90<wi100000000000

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

时间限制:1s

空间限制: 512MB

题解

因为要保证Si不为Sj的前缀。所以就可以想到哈夫曼编码。
然后发现当k=2是就是合并果子。
其实k叉树的做法也是一样的。
每次去最小的k个合并即可。
发现只有当(n-1)%(k-1)=0的时候才能恰好合并,
所以要添加k-1-(n-1)%(k-1)个权值为0高度为1的虚拟节点。
然后用堆维护一下最小值就好了。
为了保证最大高度最小,我们把高度加进比较的第二关键字。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>#include<queue>using namespace std;#define int long longint n,k,ttop, total,maxx,ans;struct word{    int times,h;    bool operator < (const word x) const{        if(times!=x.times) return times>x.times;        else return h>x.h;    }    void clear(){        times=0;        h=0;    }}w,bu,sum;priority_queue<word> q;main(){    scanf("%lld%lld",&n,&k);    for(int i=1;i<=n;i++){        scanf("%lld",&w.times);        w.h=1;        q.push(w);    }    bu.h=1;bu.times=0;    if ((n-1)%(k-1)!=0) ttop=k-1-(n-1)%(k-1);    for(int i=1;i<=ttop;i++){        q.push(bu);    }    ttop+=n;    while(ttop!=1){        sum.clear();        total=0,maxx=0;        for(int i=1;i<=k;i++){            total+=q.top().times;            maxx=max(maxx,1ll*q.top().h);            q.pop();        }        ans+=total;        sum.times=total;        sum.h=maxx+1;        q.push(sum);        ttop-=k-1;    }    printf("%lld\n%lld",ans,q.top().h-1);    return 0;}
原创粉丝点击