1367: [Baltic2004]sequence

Description

Input

Output

一个整数R

Sample Input

7
9
4
8
20
14
15
18

Sample Output

13

HINT

所求的Z序列为6,7,8,13,14,15,18.
R=13

Source

【分析】

  这题主要是要证明结论。详见hyh的论文。

  先说说结论做法:

  把序列分成m个区间,每个区间最后到达的值都是u。u为这个区间所有数的中位数。

  先做一个小小的转化,题目要求b1<b2<...b3,可以变成b1-1<=b2-2<=b3-3<=...bi-i...【经典的标号的加减,加上一个等号

  然后是这样做:

假设我们已经找到前 k 个数 a[1], a[2], … , a[k] (k<n) 的最优解,得到 m 个区间组成的队列,对应的解为 (w[1],w[2],…,w[m]),现 在要加入 a[k+1],并求出前 k+1 个数的最优解。首先我们把 a[k+1] 作为一个新区 间直接加入队尾,令 w[m+1]=a[k+1],然后不断检查队尾两个区间的解 w[m] 和
w[m+1],如果 w[m] >w[m+1],我们需要将最后两个区间合并,并找出新区间的
最优解(也就是序列 a 中,下标在这个新区间内的各项的中位数)。重复这个合
并过程,直至 w[1] ≤ w[2] ≤ … ≤ w[m] 时结束,然后继续处理下一个数。

  正确性证明:

  若某序列前半部分 a[1], a[2], … , a[n] 的最优解为 (u,u,…,u),后半部分a[n+1], a[n+2], ... , a[m] 的最优解为 (v,v,…,v),那么整个序列的最优解是什么
呢?

  若 u≤ v,显然整个序列的最优解为 (u,u,…,u,v,v,…,v) 。

  否则,设整个序列的最优解为 ( b[1],b[2],…,b[m] ),则显然 b[n] ≤ u(否则我们把前半部分的解( b[1],b[2], …,b[n]) 改为 (u,u,…,u),由题设知整个序列的解不会变坏),同理b[n+1] ≥ v。

  接下来,我们将看到下面这个事实:
对于任意一个序列 a[1] ,a[2],…,a[n],如果最优解为 (u,u,…,u),那么在满足u≤ u′≤ b[1] 或 b[n] ≤ u′≤ u 的情况下, (b[1],b[2],…,b[n]) 不会比 ( u′ ,u′ ,…,u′ )
更优。

  我们用归纳法证明 u≤ u′≤ b[1] 的情况, b[n] ≤ u′≤ u 的情况可以类似证明。

  当 n=1 时, u=a[1],命题显然成立。
当n>1 时,假设对于任意长度小于n的序列命题都成立,现在证明对于长度
为n的序列命题也成立。

  首先把 (b[1], b[2], … b[n]) 改为 (b[1], b[1], … b[1]),这
一改动将不会导致解变坏,因为如果解变坏了,由归纳假设可知a[2],a[3],…,a[n]
的中位数w>u,这样的话,最优解就应该为(u,u,…,u,w,w,…,w),矛盾。

  然后我们再把(b[1],b[1],…,b[1])改为 ( u′ ,u′ ,…,u′ ),由于 | a[1] - x | + | a[2] - x | + …+ | a[n] - x | 的几何意义为数轴上点x到点a[1], a[2], … a[n] 的距离之和,且u≤ u′≤ b[1],显然点u′ 到各点的距离之和不会比点b[1] 到各点的距离之和大,也
就是说, (b[1],b[1],…,b[n]) 不会比 (v,v,…,v) 更优。(证毕)

  再回到之前的论述,由于 b[n] ≤ u,作为上述事实的结论,我们可以得知,
将 ( b[1],b[2],…,b[n] ) 改为 (b[n],b[n],…,b[n]),再将 ( b[n+1],b[n+2],…,b[m])
改为 ( b[n+1],b[n+1], …,b[n+1]),并不会使解变坏。

也就是说,整个序列的最优
解为 ( b[n],b[n],…,b[n],b[n+1],b[n+1],…,b[n+1])。再考虑一下该解的几何意
义,设整个序列的中位数为 w,则显然令 b[n]=b[n+1]=w 将得到整个序列的最优
解,即最优解为 (w,w,…,w)。

  (以上证明来自论文ORZ)

代码:

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 1000010
#define LL long long int a[Maxn]; int myabs(int x) {return x<?-x:x;} struct node
{
int v,siz,dis,lc,rc;
}t[Maxn]; struct Ltree
{
int cnt;
int merge(int x,int y)
{
if(x==||y==) return x+y;
if(t[x].v<t[y].v) swap(x,y);
t[x].rc=merge(t[x].rc,y);
t[x].siz=t[t[x].lc].siz+t[t[x].rc].siz+;
if(t[t[x].rc].dis>t[t[x].lc].dis) swap(t[x].lc,t[x].rc);
t[x].dis=t[t[x].rc].dis+;
return x;
}
inline int top(int x) {return t[x].v;}
inline int size(int x) {return t[x].siz;}
inline void pop(int &x) {x=merge(t[x].lc,t[x].rc);}
inline int add(int x)
{
t[++cnt].v=x;t[cnt].siz=;
t[cnt].lc=t[cnt].rc=t[cnt].dis=;
return cnt;
}
}heap; int rt[Maxn],tot[Maxn];//区间
int l[Maxn],r[Maxn]; int main()
{
int n;
scanf("%d",&n);
for(int i=;i<=n;i++) {scanf("%d",&a[i]);a[i]-=i;}
int now=;
for(int i=;i<=n;i++)
{
now++;
rt[now]=heap.add(a[i]);
l[now]=r[now]=i;tot[now]=;
while(now>&&heap.top(rt[now-])>heap.top(rt[now]))
{
now--;
rt[now]=heap.merge(rt[now],rt[now+]);
tot[now]+=tot[now+];r[now]=r[now+];
while(heap.size(rt[now])*>tot[now]+)
heap.pop(rt[now]);
}
}
LL ans=;
for(int i=;i<=now;i++)
{
int xx=heap.top(rt[i]);
for(int j=l[i];j<=r[i];j++)
{
ans+=myabs(a[j]-xx);
}
}
printf("%lld\n",ans);
return ;
}

2017-01-16 15:30:21


左偏树:(上面的这份代码的左偏树还少了O(n)构建的部分。)

概念:

  优先队列 

  优先队列(Priority Queue)是一种抽象数据类型(ADT),它是一种容器,里面 有一些元素,这些元素也称为队列中的节点(node)。优先队列的节点至少要包含 一种性质:有序性,也就是说任意两个节点可以比较大小。为了具体起见我们假 设这些节点中都包含一个键值(key),节点的大小通过比较它们的键值而定。优 先队列有三个基本的操作:插入节点(Insert),取得最小节点(Minimum) 和删除 最小节点(Delete-Min)。

  可并堆

  可并堆(Mergeable Heap)也是一种抽象数据类型,它除了支持优先队列的三 个基本操作(Insert, Minimum, Delete-Min), 还支持一个额外的操作——合并操作。

  左偏树

  左偏树(Leftist Tree)是一种可并堆的实现。左偏树是一棵二叉树,它的节点 除了和二叉树的节点一样具有左右子树指针( left, right ) 外,还有两个属性:键值 和距离(dist)。

  1、外节点:节点 i 称为外节点(external node),当且仅当节点 i 的左子树或右子树为空 ( left(i) = NULL 或 right(i) = NULL );
  2、距离:点 i 的距离( dist( i ) ) 是节点 i 到它的后代 中,最近的外节点所经过的边数。特别的,如果节点 i 本身是外节点,则它的距 离为 0;而空节点的距离规定为-1 (dist(NULL) = -1)。在本文中,有时也提到一 棵左偏树的距离,这指的是该树根节点的距离。

左偏树的性质

[性质 1] 节点的键值小于或等于它的左右子节点的键值。
[性质 2] 节点的左子节点的距离不小于右子节点的距离。
[性质 3] 节点的距离等于它的右子节点的距离加 1
[引理 1] 若左偏树的距离为一定值, 则节点数最少的左偏树是完全二叉树。
[定理 1] 若一棵左偏树的距离为k,则这棵左偏树至少有 2k+1-1 个节点。
[性质 4] 一棵 N 个节点的左偏树距离最多为 [log(N+1)]-1。

性质4决定了左偏树的时间复杂度是较低的。

左偏树的合并:

int merge(int x,int y)
{
if(x==0||y==0) return x+y;
if(t[x].v<t[y].v) swap(x,y);
t[x].rc=merge(t[x].rc,y);
t[x].siz=t[t[x].lc].siz+t[t[x].rc].siz+1;
if(t[t[x].rc].dis>t[t[x].lc].dis) swap(t[x].lc,t[x].rc);
t[x].dis=t[t[x].rc].dis+1;
return x;
}

删除:

inline void pop(int &x) {x=merge(t[x].lc,t[x].rc);}

添加一个节点形成一颗新的左偏树:

inline int add(int x)
{
t[++cnt].v=x;t[cnt].siz=1;
t[cnt].lc=t[cnt].rc=t[cnt].dis=0;
return cnt;
}

各种堆的比较:

左偏树真是真短真美丽233

2017-01-16 16:08:10

最新文章

  1. C/S打包 客户端/windows程序 Inno Setup
  2. The habits of highly successful people
  3. imx6 usb otg config 配置
  4. mysq 性能分析利器
  5. [JS复习] JS 基础知识
  6. ubuntu14.04利用aliyun安装docker
  7. 高等微积分及其应用 nicholas.pdf——下载地址
  8. Jquery中的checkbox 及radio的问题
  9. Activity间中使用Intent传值
  10. Yii rules常用规则(转)
  11. Compactness问题
  12. 具有 Button 风格的 Panel(覆盖TCustomPanel的Paint函数,用到了ThemeServices)
  13. jsp之间url传值出现中文乱码
  14. html基础知识总结2
  15. jQuery的入门操作
  16. Vulkan Tutorial 05 逻辑设备与队列
  17. Open Source 开发工具集
  18. 【C++】static关键字的总结
  19. spring cloud 详解
  20. 鸟哥的linux私房菜第四版

热门文章

  1. 【转】关于C execlp函数的理解
  2. http的状态码(中英文)
  3. maven项目转成web项目
  4. cocos2d-x-2.2.6创建工程
  5. Ubuntu下安装Reids
  6. Linux学习 -- Shell基础 -- Bash变量
  7. asp读取指定目录下的文件名
  8. Hibernate中,将session绑定到线程时,在保存和查询数据的代码里,要正确的关闭session
  9. 用SqlBulkCopy批量插入数据 遇到的错误
  10. angular 实现modal windows效果(即模态窗口,半透明的遮罩层),以及bootstrap(css,components,js)的初步学习