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

做这题需要先学习左偏树《左偏树的特点及其应用》 然后做一下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. UIViewController中各方法调用顺序及功能详解

    UIViewController中各方法调用顺序及功能详解 UIViewController中loadView, viewDidLoad, viewWillUnload, viewDidUnload, ...

  2. [itint5]二叉树转换线索二叉树

    http://www.itint5.com/oj/#27 用了基于stack的中序遍历,记录一下last,就很简单了. #include <stack> /*树结点的定义(请不要在代码中定 ...

  3. WCF的通信

    [ServiceContract]    public interface IContractDemoOne    {        [OperationContract(IsOneWay=true) ...

  4. Android开发之View动画效果插补器Interpolator

    插补器Interpolator 官网描述:An interpolator defines the rate of change of an animation. This allows the bas ...

  5. 学习Java Web开发

    学习DreamWaveMX中文版的网页设计技术 HTML网页设计,这是最基本的.学习XML的一些基本知识.初步掌握一些JSCRIPT的应用. 学习JAVA语言. 这应该分成2次来进行: 第1次找一本国 ...

  6. 基于注解的SpringMVC整合JPA

    转载位置:http://www.blogjava.net/sxyx2008/archive/2010/11/02/336768.html 实体类 Department package com.sj.b ...

  7. Hibernate中的query.setFirstResult(),query.setMaxResults();

    一.query.scroll()和query.setFirstResult(),query.setMaxResults();这两种方法都可以取到一定范围内的数据,用来数据分页显示.那么两者区别,以及两 ...

  8. C#中哈希表与List的比较

    简单概念 在c#中,List是顺序线性表(非链表),用一组地址连续的存储单元依次存储数据元素的线性结构. 哈希表也叫散列表,是一种通过把关键码值映射到表中一个位置来访问记录的数据结构.c#中的哈希表有 ...

  9. [.NET WebAPI系列01] WebAPI 简单例子

    [源] 来自微软WebAPI官方视频,Introduction to the ASP.NET Web API --Uniform Interface -- Demo-Using convention ...

  10. windows ssh RPi 2B

    /************************************************************************* * windows ssh RPi 2B * 声明 ...