PS:如果读过题了可以跳过题目描述直接到题解部分

提交链接:洛谷 P2168 [NOI2015] 荷马史诗

题目

题目背景

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

题目描述

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

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

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

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

一个字符串被称为 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 个非负整数 w[i],表示第 i 种单词的出现次数。

输出格式

输出包括 2 行。

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

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

样例1

样例输入1

4 2
1
1
2
2

样例输出1

12
2

样例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

最长字符串 s[i] 的长度为 2 。

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

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

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

样例 2 解释

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

数据规模与约定

所有测试数据的范围和特点如下表所示(所有数据均满足 0 < w[i]≤10^11):

测试点编号 n 的规模 k 的规模 备注
1 n=3 k=2
2 n=5 k=2
3 n=16 k=2 所有 w[i] 均相等
4 n=1 000 k=2 w[i]在取值范围内均匀随机
5 n=1 000 k=2
6 n=100 000 k=2
7 n=100 000 k=2 所有 w[i] 均相等
8 n=100 000 k=2
9 n=7 k=3
10 n=16 k=3 所有 w[i] 均相等
11 n=1 001 k=3 所有 w[i] 均相等
12 n=99 999 k=4 所有 w[i] 均相等
13 n=100 000 k=4
14 n=100 000 k=4
15 n=1 000 k=5
16 n=100 000 k=7 w[i]在取值范围内均匀随机
17 n=100 000 k=7
18 n=100 000 k=8 w[i]在取值范围内均匀随机
19 n=100 000 k=9
20 n=100 000 k=9

提示

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

评分方式

对于每个测试点:

若输出文件的第 1 行正确,得到该测试点 40% 的分数;

若输出文件完全正确,得到该测试点 100% 的分数。

题解

哈夫曼编码树

详见我之前发过的文章

未来计算 3219 未来算算 1260 Huffman编码树

就题调整

对于这道题而言,因为可以用不同进制的数,所以也就不一定要用左子节点和右子节点,而可以直接用son数组(我偷懒写的s),操作基本上是一样的,就取权值最小的前k个,合成成一棵子树。

取最小的前k个,我用的是手写堆排序,不想手写的其实也可以用其他函数代替。

但需要注意的是,直接像二进制一样建树可能会出现上层节点不到k个的情况,这个时候其实并不是最优,所以需要把下面的节点往上面挪。我看其他博主有用空节点占位的方法,但我是直接计算合并的第一棵树应该合并多少个节点,公式如下:node=n%(k-1)(二进制的时候不需要计算,要提前进行特判),但当node=1的时候,相当于只合并一个节点,这就是没有必要的,就可以直接合并k个节点。

另外,题目不仅要求最后要总长度最短,还要求要最长的字符串长度最短,即编码树的树高尽可能矮。因此在节点信息中,我加入了子树深度来对排序进行影响,在权值相同的情况下,将子树深度较小的排在前面。

最后,从根节点进行深搜,更新节点到根节点的距离(即字符串长度)和最远距离(即最长的字符串长度)。

代码实现

我的代码可能不太简洁,但反正洛谷是过了的。

//洛谷 P2168 [NOI2015] 荷马史诗
#include<iostream>
#include<cstdio>
using namespace std;
long long n;
int k;
int a[110000];//堆 保存子树节点序号
int cnt;
int t;
unsigned long long ans;
unsigned long long maxx;struct node{unsigned long long w;//节点权值unsigned long long h;//该节点与根节点的距离int s[11];unsigned long long d;//子树深度
}w[440000];//堆增加节点
void insert(int x){int p=++cnt;a[p]=x;while(p!=1&&(w[a[p/2]].w>w[a[p]].w||(w[a[p/2]].w>w[a[p]].w&&w[a[p/2]].d>w[a[p]].d))){swap(a[p/2],a[p]);p/=2;}
}//堆弹出
void pop(){swap(a[cnt],a[1]);--cnt;int p=1;int k=1;while(1){if((p<<1)<=cnt&&(w[a[k]].w>w[a[(p<<1)]].w||(w[a[k]].w==w[a[(p<<1)]].w&&w[a[k]].d>w[a[(p<<1)]].d))){k=(p<<1);}if(((p<<1)|1)<=cnt&&(w[a[k]].w>w[a[(p<<1)|1]].w||(w[a[k]].w==w[a[(p<<1)|1]].w&&w[a[k]].d>w[a[(p<<1)|1]].d))){k=(p<<1|1);}if(k==p){break;}swap(a[k],a[p]);p=k;}
}//建哈夫曼编码树
void build(int x){++t;for(int i=1;i<=x&&cnt;++i){w[t].w+=w[a[1]].w;w[t].s[i]=a[1];w[t].d=max(w[t].d,w[a[1]].d+1);pop();}
}//深搜更新与根节点的距离
void dfs(int x,unsigned long long h){w[x].h=h;for(int i=1;i<=k;++i){if(w[x].s[i]){dfs(w[x].s[i],h+1);}}if(h>maxx){maxx=h;}
}int main(){scanf("%lld%d",&n,&k);for(int i=1;i<=n;++i){scanf("%lld",&w[i].w);insert(i);w[i].d=1;}t=cnt;if(cnt!=1){build(k==2?2:(n%(k-1)==1?k:n%(k-1)));//第一棵子树需计算合并节点数}insert(t);while(cnt!=1){build(k);insert(t);}dfs(t,0);for(int i=1;i<=n;++i){ans+=w[i].w*w[i].h;}printf("%lld\n%lld\n",ans,maxx);return 0;
}

洛谷 P2168 [NOI2015] 荷马史诗相关推荐

  1. 【洛谷P2168】荷马史诗

    题目描述 追逐影子的人,自己就是影子 --荷马 Allison 最近迷上了文学.她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的<荷马史诗>.但是由<奥德赛&g ...

  2. P2168 [NOI2015] 荷马史诗(哈夫曼编码树)

    传送门 文章目录 题目描述 解析 细节 代码 题目描述 解析 其实就是构造一棵树 另所有带权点都为叶子节点 其代价为权值与深度的乘积 求最小代价及最小代价下的最小深度 可以看成一开始有n棵小树 每次把 ...

  3. [NOI2015]荷马史诗【哈夫曼编码】

    [NOI2015]荷马史诗 推荐一篇题解 (感觉自己讲不清楚所以不如直接粘题解) 观察之后发现这就是哈夫曼编码,于是按照编码方式构造即可. #include <bits/stdc++.h> ...

  4. NOI2015 荷马史诗

    题目链接:戳我 首先看出来这是一个哈夫曼树! 然后就按照这里面哈夫曼树那一点说的,就可以A掉这个题啦 #include<iostream> #include<cstdio> # ...

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

    4198: [Noi2015]荷马史诗 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 127 Solved: 80 Description 追逐影子的 ...

  6. 洛谷P2168 荷马史诗 [NOI2015]

    题目描述 追逐影子的人,自己就是影子 --荷马 Allison 最近迷上了文学.她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的<荷马史诗>.但是由<奥德赛&g ...

  7. NOI2015 Day2 T1 荷马史诗(洛谷P2168)

    题目描述 追逐影子的人,自己就是影子 --荷马 Allison 最近迷上了文学.她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的<荷马史诗>.但是由<奥德赛&g ...

  8. 洛谷 P2168 荷马史诗(抄)

    题目描述 追逐影子的人,自己就是影子 --荷马 Allison 最近迷上了文学.她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的<荷马史诗>.但是由<奥德赛&g ...

  9. ajax荷马史诗,荷马史诗(8)

    <奥德赛>(Odyssey) 奥德修斯的希腊文原意是"麻烦":他既带给别人麻烦,自己也遭遇麻烦 <埃阿斯和卡珊德拉>(Ajax and Cassandra) ...

  10. [NOI 2015]荷马史诗

    Description 追逐影子的人,自己就是影子. --荷马 Allison 最近迷上了文学.她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的<荷马史诗>.但是由& ...

最新文章

  1. 由SELECT *引发的多个生产故障,问题藏太深了吧……
  2. 区块链的技术——账本是去中心化的分布式存储,加密+校验(哈希二叉树)+多数选举来防止篡改...
  3. 计算机科学与技术与cs,CSgo! | 遇见CS—带你走进传说中的计算机专业
  4. 直播报名 | CUDA优化:高性能库cuBLAS使用指南
  5. jpa加密_使用JPA侦听器的数据库加密
  6. java二维数组水平翻转,C 语言 利用二维数组实现对输入的数组进行翻转
  7. Project FreeEIM 2.0:重现失落的飞鸽传书
  8. [Python+sklearn] 计算混淆矩阵 confusion_matrix()函数
  9. 2021-08-24自然语言处理预训练模型的研究综述 - 知网论文
  10. 前端数组如何传到后台
  11. python数据分析建模-十分钟搞懂“Python数据分析”
  12. (转)协议森林10 魔鬼细节 (TCP滑窗管理)
  13. 计算机课的英语怎么念,电脑课是什么意思
  14. vb mysql_VB6 如何连接MYSQL数据库
  15. 利用NT6.X HDD Installer_v3.0.exe安装电脑系统
  16. Redis6笔记分享(从NoSQL基础到分布式锁的介绍)
  17. hp打印机装不上服务器系统安装,惠普1210打印机驱动为什么一直安装不上?
  18. zstd优秀的数据压缩算法,大数据小数据包
  19. echarts 四川省地图成都默认高亮
  20. su命令切换到root用户_如何在Linux中使用su命令成为超级用户或root?

热门文章

  1. 中国省,市,区 json数据
  2. 体系结构14_控制相关的动态解决技术
  3. marvell raid linux,Marvell SATA Raid控制器 驱动程序下载——更新 Marvell 软件
  4. 【JSP篇】——6.JSP之小学生在线答题系统【综合实战篇】
  5. 监控视频平台LiveNVR如何给摄像头视频添加文字水印和图片水印
  6. 一文搞懂经济数据中M0 M1 M2
  7. totolink服务器未响应,totolink路由器登陆页面打不开怎么办
  8. Spring5-完全注解开发【之】第一步,先实现功能(增删改查),再讲解陌生代码
  9. realtek没有禁用前面板_为什么HD声卡必须禁用前面板插孔检测前置耳机和麦克才可以有声...
  10. 新浪微博API错误代码大全