我才不是萝莉控呢
2015-09-04 22:26
253 查看
题意
有一个长度为nn 的正整数数组AA,满足Ai≥Ai+1A_i \ge A_{i+1},现在构造一个数组BB,令Bi=∑inAiB_i = \sum\limits_{i}^{n}A_i。现在,有一个n∗nn * n 的网格图,左下角坐标是(1,1)(1, 1),右上角坐标是(n,n)(n, n)。有一个人正在坐标为(n,1)(n, 1)的位置,每一时刻,如果他现在在(x,y)(x, y),他可以选择走到(x−1,y+1)(x -1,y + 1) 或者(x,⌊y2⌋)(x, \lfloor\frac{y}{2}\rfloor),如果选择后者,他要支付BxB_x的代价。
现在他想走到(1,1)(1, 1),你可以告诉他他支付的代价最少是多少吗?注意在任何时候他都不能离开这个网格图。
分析
引用题解:这个问题的答案就是数组 A 中所有元素的哈夫曼树的权值。
因为数组是有序的,所以在哈夫曼树中的深度一定是单调不减的。我们考虑每一个位置,把fi,j f_{i,j} 看成现在已经放入了下标比 ii 小的所有节点,剩余的叶子节点有 jj 个。
那么我们每一次有两种选择,
第一种是把所有叶子节点都扩展出两个后继,这时剩下所有节点的深度都增加了11,所以付出的代价是 ∑k=i+1nAk\sum\limits_{k=i+1}^{n}A_k,状态变成了 f2∗i,jf_{2*i,j};
第二种是把第i i 个数填在一个叶子上,这时状态变成了 fi+1,j−1f_{i+1,j−1}。最终的答案就是 min(fn+1,k),(k>0)min( {f_{n+1,k}}),(k > 0)。
我们把这个 DP 过程倒过来,就变成了题目中描述的走路的样子。所以只需要求哈夫曼树就好了,这是经典算法(合并果子)。
代码
用priority_queue略慢…建议用make_heap#include <cstdio> #include <queue> using namespace std; typedef long long LL; const int N = 1e5 + 10; int n,a ; priority_queue< LL , vector<LL> , greater<LL> > s; int main() { int T; scanf("%d",&T); while (T --) { while (!s.empty()) s.pop(); scanf("%d",&n); for (int i = 1;i <= n;i ++) { scanf("%d",&a[i]); s.push(a[i]); } LL ans = 0; for (int i = 1;i < n;i ++) { LL a = s.top(); s.pop(); LL b = s.top(); s.pop(); s.push(a + b); ans += a + b; } printf("%lld\n",ans); } }
相关文章推荐
- Android 自定义View流程
- matlab读取/播放视频的函数(1)
- 触发器
- java.util之Iterable与Iterator
- Linux系统管理 --磁盘管理与系统管理
- JavaScript基础知识
- [转载]Eclipse自定义快捷键导出和导入方法
- 华为机试测试- 大数相加
- 获取二叉树深度叶子数
- Linux分享之iptables:防火墙以及网络协议基本原理
- Kaggle系列——Titanic 80%+精确度纪录
- netstat 的10个基本用法
- hdu 4355 Party All the Time 三分
- Android内存管理机制详解
- easyui中Tab的tools按钮刷新当前tab
- haproxy+keepalived实现高可用集群
- 员工管理系统
- YDKJ 读书笔记 01 Function vs. Block Scope
- HDU 4028 The time of a day(DP)
- hdu 1542(离散化+扫描线)