我觉得我要改一下签名了……怎么会有窝这么啰嗦的人呢?

做这题需要先学习左偏树《左偏树的特点及其应用》 然后做一下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)的更多相关文章

  1. 左偏树(DP)问题

    问题:A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ woul ...

  2. 『左偏树 Leftist Tree』

    新增一道例题 左偏树 Leftist Tree 这是一个由堆(优先队列)推广而来的神奇数据结构,我们先来了解一下它. 简单的来说,左偏树可以实现一般堆的所有功能,如查询最值,删除堆顶元素,加入新元素等 ...

  3. Monkey King(左偏树 可并堆)

    我们知道如果要我们给一个序列排序,按照某种大小顺序关系,我们很容易想到优先队列,的确很方便,但是优先队列也有解决不了的问题,当题目要求你把两个优先队列合并的时候,这就实现不了了 优先队列只有插入 删除 ...

  4. POJ3666-Making the Grade(左偏树 or DP)

    左偏树 炒鸡棒的论文<左偏树的特点及其应用> 虽然题目要求比论文多了一个条件,但是……只需要求非递减就可以AC……数据好弱…… 虽然还没想明白为什么,但是应该觉得应该是这样——求非递减用大 ...

  5. k短路模板(洛谷P2483 [SDOI2010]魔法猪学院)(k短路,最短路,左偏树,priority_queue)

    你谷数据够强了,以前的A*应该差不多死掉了. 所以,小伙伴们快来一起把YL顶上去把!戳这里! 俞鼎力的课件 需要掌握的内容: Dijkstra构建最短路径树. 可持久化堆(使用左偏树,因其有二叉树结构 ...

  6. 洛谷P1552 [APIO2012] 派遣 [左偏树,树形DP]

    题目传送门 忍者 Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都 ...

  7. Luogu P1552 [APIO2012]派遣【左偏树】By cellur925

    题目传送门 $Chat$ 哈哈哈我xj用dfs序乱搞竟然炸出了66分....(其实还是数据水,逃) $Sol$ 首先我们应该知道,一个人他自己的满意度与他子树所有节点的领导力是无关的,一个人的满意度受 ...

  8. BZOJ 1455 罗马游戏 ——左偏树

    [题目分析] 左偏树的模板题目,大概就是尽量维护树的深度保持平衡,以及尽可能的快速合并的一种堆. 感觉和启发式合并基本相同. 其实并没有快很多. 本人的左偏树代码自带大常数,借鉴请慎重 [代码] #i ...

  9. 【BZOJ-1455】罗马游戏 可并堆 (左偏树)

    1455: 罗马游戏 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1355  Solved: 561[Submit][Status][Discuss] ...

随机推荐

  1. 【BZOJ 1045】 1045: [HAOI2008] 糖果传递

    1045: [HAOI2008] 糖果传递 Description 有n个小朋友坐成一圈,每人有ai个糖果.每人只能给左右两人传递糖果.每人每次传递一个糖果代价为1. Input 第一行一个正整数n& ...

  2. Android中如何取消调转界面后EditText默认获取聚焦问题

    最近在做一个项目,当我点击跳转至一个带有EditText的界面后,模拟器中的软键盘会自动弹出,严重影响了用户体验.在网上找了资料,现总结如下. 我们知道,EditText有一个 android:foc ...

  3. SaaS系列介绍之一: SaaS的前身ASP介绍

    1. 引言 未来将越来越不可预测,这是新经济最具挑战性的方面之一.商务和技术上的瞬息万变会产生变化,这既可以看作要防范的威胁,也可以看作应该欢迎的机遇.                         ...

  4. AD15高版软件卡不卡,问题解决大讨论

    AD高版软件很卡(包括13 14 15版),这是我遇到过的问题,大家都遇到过的问题, 这里我分享一个解决办法:也请给位有什么好的方法也一起分享. 问题1卡:打开AD15软件, 按住鼠标中键 放大 或 ...

  5. C++动态链接库测试实例

    前话 上一章节我导出了一个动态链接库 要使用该链接库,我们还需要该链接库对外公开的函数,即头文件 下面开始实例 测试实例 第一步--将动态链接库的dll.lib.和头文件导入项目中 文件目录如下: 项 ...

  6. JS选中OPTION

    var obj_prov = document.getElementById("prov"); var prov_text = obj_prov.options[obj_prov. ...

  7. c++ const 关键字 学习笔记

    const简单介绍: 1不再使用c中的#define,c++默认不给const定义的变量分配内存,所以它默认的是仅本文件可以看到该变量(即internal linkage), const int bu ...

  8. objective-C 自定义对象归档的实现

    自定义对象要实现归档必须实现NSCoding协议 NSCoding协议有两个方法,encodeWithCoder方法对对象的属性数据做编码处理,initWithCoder解码归档数据来初始化对象. # ...

  9. Unicode汉字编码表

    U+  0   1  2  3  4   5  6   7   8   9   A  B  C  D  E  F  ------------------------------------------ ...

  10. sizeof(结构体)的计算

    摘要: 经常被计算结构体的sizeof给搞晕,于是找了个时间,静下心来,搞定它. 一.为什么结构体计算这么乱? 答案是字节对齐,计算机存储系统中以Byte为单位存储数据,不同数据类型所占的空间不同,如 ...