【Baltic 2004】数字序列(有改动)

原题在BZOJ上的链接

题目描述

题意:给你一个长度为n的整数序列A。把它变成一个不降的序列。求改动的最小代价,代价为更改前后的数字大小的差值。

就是没有了原题中改动次数最小的限制。

题解

考试时看到这到题就以为是数字序列了…
不说废话了。
既然没有操作次数最小的要求,那么就只用考虑最小代价了(废话)
怎么使代价最小呢?对于一个序列,如果它是单调不降的,我们显然不用去单独管它。
如果有减小的呢? 若单独考虑考虑一段递减序列,那么自然是变成它们的中位数。为什么呢?求函数f(x)=|x-h1|+|x-h2|+|x-h3|….+|x-hn|的最小值总会吧,一根数轴即可搞定。
但我们显然不能只考虑一段区间,对于我们分出的每一段区间,必须要他们的中位数不降,否则不满足题意。对于这样的区间,可以用一个栈来维护。

那么只用考虑在栈顶前后两个区间不合法时如何合并两段区间了。
这里似乎只要能求出合并后的中位数即可,其他的数据(统计答案时要用,具体看代码)都可以直接开数组记录。
那么讨论如何求中位数,看出来是个动态求中位数了吧,是不是想到用两个堆,保证他们的size差不大于1。这道题要支持合并的话就左偏树。

但观察到这道题还有一个性质,因为只有在后面的区间的中位数小于前一个区间时才会合并,那么合并后两者的中位数必然相对与前一个减小,那么开个大根堆的话就只用在合并之后保留一半多一个元素即可,堆顶就是中位数了!
统计答案的话暴力O(n)就可以了。
至于这样做正确性的证明,可以参考 国家集训队2005论文集_黄源河 的论文(orz)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<queue>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值