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] ...
随机推荐
- [itint5]两有序数组的中位数
这个题和leetcode的基本一样.用了更好点的思路.在A中折半猜是不是中位数,A中没有后在B中猜.最后猜到B[j]<=A[i]<=B[j+1],此时,无论奇偶(2k+1或者2k个),A[ ...
- [topcoder]ZigZag
http://community.topcoder.com/stat?c=problem_statement&pm=1259&rd=4493 动态规划题.如果不用DP,暴力的应当在2^ ...
- JNDI学习总结(二)——Tomcat下使用C3P0配置JNDI数据源
一.C3P0下载 C3P0下载地址:http://sourceforge.net/projects/c3p0/files/?source=navbar
- 191. Number of 1 Bits
题目: Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also ...
- Android开发经验记录
一. 代码规范 定一个规范的主要目的,是为了让不同的开发人员写的代码能保持一致性,方便别人看自己的代码.另外,对个人来说,也能起到让自己看着舒服的作用. 1. 基本 * 使用UTF-8 ...
- fork()和vfork()区别
fork创建进程,子进程和父进程不一定谁先执行 vfork创建的进程,不分配新的资源,子进程用父进程相应的资源,且子进程先执行. 用vfork创建的进程,资源共享,那么,数据是不是不牵扯通信间的机制, ...
- C#创建XML文件并保存
随着XML的普及以及在动态WEB应用程序中大量应用,如何通过.NET创建,删除,修改XML文件变的也来也重要了.一个简单的概念是,XML文件跟大的文本文件并没有什么区别,同时它是先于.NET出现,很多 ...
- Android横竖屏切换总结
Android横竖屏切换总结(Android资料) Android横竖屏要解决的问题应该就两个: 一.布局问题 二.重新载入问题 1.布局问题:如果不想让软件在横竖屏之间切换,最简单的办法就是在项目的 ...
- SQLite支持的SQL数据操作
事务处理 Posted on 2013 年 1 月 1 日 by 林溪 事务为一组SQL命令的集合,这些SQL命令在执行时不可进行分割,即要么全部执行这些SQL命令,要么一个都不进行执行,事务操作 ...
- MySQL timed_mutexes
提要: MySQL 5.5.39 Release版本正式从源码里删除了全局参数timed_mutexes.timed_mutexes原本用来控制是否对Innodb引擎的mutex wait进行 计时统 ...