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] ...
随机推荐
- C++ DLL 模板 .
C++ DLL 模板 1.使用VS2005创建Win32 DLL项目,选择空项目,然后加入CppDll.h和CppDll.cpp文件. 2.修改CppDll.h和CppDll.cpp文件使之成为需要的 ...
- ANDROID_MARS学习笔记_S01_008Linear_layout例子
1.netstone_layout.xml <?xml version="1.0" encoding="utf-8"?> <LinearLay ...
- Oracle 学习笔记 常用查询命令篇
1.查询某个用户下有多少张表 有时候很有用 select count(*) from dba_tables t where t.owner='SCOTT';
- ripple
ripple模拟器非常好用,chrome上的插件
- ARM7ldr指令与ldr伪指令
ldr伪指令的第二个操作数之前有个=,意思是第一个操作书 = 第二个操作数,相当明了 核心就在于对于用.word指令在.text段里另外定义一段内存,用ldr r0,[pc + x(可以算出.text ...
- LINUX进程优先级实现
首先linux进程优先级的范围是-20到19 将当前目录下的documents目录打包,但不希望tar占用太多CPU: nice -19 tar zcf pack.tar.gz documents 这 ...
- android 引用 project以及下拉刷新开源类库Android-PullToRefresh 的使用
Android-PullToRefresh 是一个github上的开源下拉刷新类库, GitHub .此外,该作者还有另外一个实用度和关注量极高的项目–另一种Android ActionBar的实现 ...
- System.Drawing.Design.UITypeEditor自定义控件属性GetEditStyle(ITypeDescriptorContext context),EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.C ...
- Oracle Length 和 Lengthb 函数说明 .(用来判断记录值里是否有中文内容)
一.官网的说明 http://download.oracle.com/docs/cd/E11882_01/server.112/e26088/functions088.htm#SQLRF00658 P ...
- java vm args
这个问题主要还是由这个问题 java.lang.OutOfMemoryError: Java heap space 引起的.第一次出现这样的的问题以后,引发了其他的问题.在网上一查可能是JAVA的堆栈 ...