POJ3016-K-Monotonic(左偏树+DP)
我觉得我要改一下签名了……怎么会有窝这么啰嗦的人呢?
做这题需要先学习左偏树《左偏树的特点及其应用》 然后做一下POJ3666,这题的简单版。
思路:
考虑一下维护中位数的过程
原数组为A,找到的不降数列为B
当对于A的前n个数已经找好了最优解B[1…n],可知此时A被分成很多块,并被一些大顶堆记录,假设第i块有num个数,那么第i个堆维护这一块的最小的(num+1)/2个数,堆顶即为中位数。
假设已经处理好前7个数,被分为两块 ([a,b],c,d) ([h,e],f) (每一块按升序排列,[]中的数是堆里面维护的。
因为数列是不降的,所以b≤e
当新添加一个元素的时候,设为x,如果x≤e,将需要向前合并。
那么新的块应该是……分两种情况……
1.x>h ([h,x],e,f)
2.x<h ([x,h],e,f)
设新的中位数是val=max(h, x) 分类讨论一下可以发现改变的值是(e-val)+(val-x)
这里假设是([x,h],e,f)
当h<b时,需要继续向前合并。
合并之后是([x,h,a,b],c,d,e,f) (顺序已经不确定了,只能确定栈中元素和栈顶是b
可以发现大小为偶数的块和偶数的块合并,合并后的堆不需要弹出元素。
合并前([a,b],c,d) 的中位数是b ([x,h],e,f)的中位数是h, 合并后的中位数的b
可知答案改变都是发生在集合([x,h],e,f)中的,我们又知道b≤e(上面提到过),那么很容易得到答案是不变哒!(就是把(h-x)+(h-h)+(e-h)+(f-h)变成了(b-x)+(b-h)+(e-b)+(f-b),值是一样的
上面是偶数和偶数合并,继续讨论前一块奇数和后一块偶数合并。
设前一块是([a,b],c) 中位数是b,后一块是([d,e],f,g)中位数是e,合并后不需要弹出,中位数是b,类似上面的情况,我们可以得出b≤f,所以答案仍然不变。
前一块偶数,后一块奇数
([a,b],c,d)中位数是b ([e,f],g)中位数是f 合并后不需要弹出 中位数是b 其中(f<b≤g)
那么答案由([e,f],g)的改变产生,f的左右两边是可以抵消掉的,改变只会因为f,改变的值是b-f
前一块奇数,后一块奇数
设前一块是([a,b],c) 中位数是b,后一块是([d,e],f,)中位数是e 其中e<b≤f
合并后弹出元素b,中位数为max(a,e),设为val
那么答案改变就是b-e
到此,所有情况都讨论完了ˊ_>ˋ
结论:当一个块和前面的块合并时,如果当前块的数量为偶数,答案不变,否则答案增加(前一块的中位数-当前块的中位数)
代码:
- /*****************************************
- Problem: 3016 User: G_lory
- Memory: 12676K Time: 1797MS
- Language: G++ Result: Accepted
- *****************************************/
- #include <iostream>
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- const int N = ;
- const int INF = 0x5f5f5f5f;
- typedef long long ll;
- struct LTree {
- int l, r, sz;
- int key, dis;
- bool operator<(const LTree lt) const {
- return key < lt.key;
- }
- } tr[N];
- int cnt_tr;
- int NewTree(int k) {
- tr[++cnt_tr].key = k;
- tr[cnt_tr].l = tr[cnt_tr].r = tr[cnt_tr].dis = ;
- tr[cnt_tr].sz = ;
- return cnt_tr;
- }
- int Merge(int x, int y) {
- if (!x || !y) return x + y;
- if (tr[x] < tr[y]) swap(x, y);
- tr[x].r = Merge(tr[x].r, y);
- if (tr[tr[x].l].dis < tr[tr[x].r].dis) swap(tr[x].l, tr[x].r);
- tr[x].dis = tr[tr[x].r].dis + ;
- tr[x].sz = tr[tr[x].l].sz + tr[tr[x].r].sz + ;
- return x;
- }
- int Top(int x) {
- return tr[x].key;
- }
- void Pop(int &x) {
- x = Merge(tr[x].l, tr[x].r);
- }
- int root[N], num[N];
- void cal(int a[], int n, int ans[]) {
- int res;
- cnt_tr = res = ;
- int cnt = ;
- for (int i = ; i < n; ++i) {
- root[++cnt] = NewTree(a[i]);
- num[cnt] = ;
- while (cnt > && Top(root[cnt]) < Top(root[cnt-])) {
- cnt--;
- if (num[cnt+]&) res += Top(root[cnt]) - Top(root[cnt+]);
- root[cnt] = Merge(root[cnt], root[cnt+]);
- num[cnt] += num[cnt+];
- while (tr[root[cnt]].sz* > num[cnt]+) {
- Pop(root[cnt]);
- }
- int now = Top(root[cnt]);
- }
- ans[i] = res;
- }
- }
- int a[N], b[N], c[N];
- int in[N][N], de[N][N];
- int dp[N][N];
- int main() {
- //freopen("in", "r", stdin);
- int n, k;
- while (~scanf("%d%d",&n, &k) && n) {
- for (int i = ; i <= n; ++i) {
- scanf("%d", a+i);
- b[i] = a[i]-i;
- c[i] = -a[i]-i;
- }
- for (int i = ; i <= n; ++i) {
- cal(c+i, n-i+, de[i]+i);
- cal(b+i, n-i+, in[i]+i);
- }
- for (int i = ; i <= n; ++i) dp[][i] = INF;
- for (int i = ; i <= k; ++i) {
- dp[i][] = ;
- for (int j = ; j <= n; ++j) {
- dp[i][j] = INF;
- for (int p = ; p < j; ++p) {
- dp[i][j] = min(dp[i][j], dp[i-][p] + min(in[p+][j], de[p+][j]));
- }
- }
- }
- printf("%d\n", dp[k][n]);
- }
- return ;
- }
POJ3016-K-Monotonic(左偏树+DP)的更多相关文章
- 左偏树(DP)问题
问题:A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ woul ...
- 『左偏树 Leftist Tree』
新增一道例题 左偏树 Leftist Tree 这是一个由堆(优先队列)推广而来的神奇数据结构,我们先来了解一下它. 简单的来说,左偏树可以实现一般堆的所有功能,如查询最值,删除堆顶元素,加入新元素等 ...
- Monkey King(左偏树 可并堆)
我们知道如果要我们给一个序列排序,按照某种大小顺序关系,我们很容易想到优先队列,的确很方便,但是优先队列也有解决不了的问题,当题目要求你把两个优先队列合并的时候,这就实现不了了 优先队列只有插入 删除 ...
- POJ3666-Making the Grade(左偏树 or DP)
左偏树 炒鸡棒的论文<左偏树的特点及其应用> 虽然题目要求比论文多了一个条件,但是……只需要求非递减就可以AC……数据好弱…… 虽然还没想明白为什么,但是应该觉得应该是这样——求非递减用大 ...
- k短路模板(洛谷P2483 [SDOI2010]魔法猪学院)(k短路,最短路,左偏树,priority_queue)
你谷数据够强了,以前的A*应该差不多死掉了. 所以,小伙伴们快来一起把YL顶上去把!戳这里! 俞鼎力的课件 需要掌握的内容: Dijkstra构建最短路径树. 可持久化堆(使用左偏树,因其有二叉树结构 ...
- 洛谷P1552 [APIO2012] 派遣 [左偏树,树形DP]
题目传送门 忍者 Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都 ...
- Luogu P1552 [APIO2012]派遣【左偏树】By cellur925
题目传送门 $Chat$ 哈哈哈我xj用dfs序乱搞竟然炸出了66分....(其实还是数据水,逃) $Sol$ 首先我们应该知道,一个人他自己的满意度与他子树所有节点的领导力是无关的,一个人的满意度受 ...
- BZOJ 1455 罗马游戏 ——左偏树
[题目分析] 左偏树的模板题目,大概就是尽量维护树的深度保持平衡,以及尽可能的快速合并的一种堆. 感觉和启发式合并基本相同. 其实并没有快很多. 本人的左偏树代码自带大常数,借鉴请慎重 [代码] #i ...
- 【BZOJ-1455】罗马游戏 可并堆 (左偏树)
1455: 罗马游戏 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1355 Solved: 561[Submit][Status][Discuss] ...
随机推荐
- DevSecOps 实施篇!系列(二)
想在自己公司建立 DevSecOps 计划?没问题,企业规模无论大小,都可轻松实现.这里有5个基本的 DevSecOps 原则可以帮助你启动.当然,如果你对 DevSecOps 还不太熟悉,不妨先看看 ...
- IDEA 创建maven-web project失败一例
今天使用IDEA创建WEB-APP总是失败,经排查原来是MAVEN环境没配置好!!! 配置: M2_HOME--->maven解压目录 path---->%M2_HOME%\bin\
- iOS中关于KVC与KVO知识点
iOS中关于KVC与KVO知识点 iOS中关于KVC与KVO知识点 一.简介 KVC/KVO是观察者模式的一种实现,在Cocoa中是以被万物之源NSObject类实现的NSKeyValueCodin ...
- linux系统相关的任务[fg、bg、jobs、&、ctrl + z]
转自: http://blog.chinaunix.net/space.php?uid=20697318&do=blog&id=1891382 fg.bg.jobs.&.ctr ...
- log4j:ERROR A "org.jboss.logging.appender.FileAppender" object is not assignable to a "org.apache.lo .
log4j:ERROR A "org.jboss.logging.appender.FileAppender" object is not assignable to a &quo ...
- linux应用程序问题
---- 1 ----
- 【HDOJ】1914 The Stable Marriage Problem
稳定婚姻问题,Gale-Shapley算法可解. /* 1914 */ #include <iostream> #include <sstream> #include < ...
- 推荐:ThoughtWorks(中国)程序员读书雷达
部分转自张逸的博客:http://agiledon.github.io/blog/2013/04/17/thoughtworks-developer-reading-radar/ 长久以来一直对程序员 ...
- SSMS错误代码大全
0 操作成功完成. 1 功能错误. 2 系统找不到指定的文件. 3 系统找不到指定的路径. 4 系统无法打开文件. 5 拒绝访问. 6 句柄无效. 7 存储控制块被损坏. 8 存储空间不足,无法处理此 ...
- Rman实现数据库迁移
Rman实现数据库迁移(从库A迁移到库B)环境:服务器A:Oracle10g+AS3服务器B:Oracle10g+AS4准备工作: 1 在数据库B上建立与库A相同的目录结构(若由于磁盘空间等原因可以用 ...