原题请见《左偏树的特点及其应用》BY 广东省中山市第一中学 黄源河

luogu

题意

给出序列\(a[1...n]\),要求构造一个不下降序列\(b[1...n]\)使得\(\sum_{i=1}^{n}|a_i-b_i|\)最小。

sol

首先很自然地能够想到,构造出来的序列\(b[1...n]\)一定可以划分成\(m\)段\((1\le{m}\le{n})\),每段内数字全部相同。

我们把每一段的数字提取出来分别为\(c[1...m]\)。

如果对每一段的\(c[i]\)都取最优的话,那么一定是去这一段中\(a[i]\)的中位数。

但是取中位数可能会导致序列\(c\)不满足非降,这个时候就需要把相邻的两个不合法的段合并成一段。

所以就需要维护中位数。

左偏树。对于一个长度为\(x\)的段,左偏树中保存这一段中前\(\lfloor\frac{x+1}{2}\rfloor\)小的数字,易知这些数里面最大的那个就是中位数,合并的时候直接合并两棵左偏树。

因为\(\lfloor\frac{x+1}{2}\rfloor+\lfloor\frac{y+1}{2}\rfloor=\lfloor\frac{x+y+1}{2}\rfloor-1\)当且仅当\(x,y\)均为奇数,所以这种情况要弹掉堆顶元素。

复杂度\(O(n\log{n})\)

注:洛谷的题目是要求构造一个递增序列,可以采用减下标的方法,即输入时把每个数都减去对应下表,输出时再加上,这样就可以完成不下降序列和递增序列的转换。

code

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. #define ll long long
  5. inline int gi()
  6. {
  7. int x=0,w=1;char ch=getchar();
  8. while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  9. if (ch=='-') w=0,ch=getchar();
  10. while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
  11. return w?x:-x;
  12. }
  13. const int N = 1e6+5;
  14. int n,key[N],ls[N],rs[N],dis[N],S[N],ed[N],top;
  15. ll ans;
  16. int merge(int A,int B)
  17. {
  18. if (!A||!B) return A|B;
  19. if (key[A]<key[B]) swap(A,B);
  20. rs[A]=merge(rs[A],B);
  21. if (dis[ls[A]]<dis[rs[A]]) swap(ls[A],rs[A]);
  22. dis[A]=dis[rs[A]]+1;
  23. return A;
  24. }
  25. int main()
  26. {
  27. n=gi();
  28. for (int i=1;i<=n;++i) key[i]=gi();
  29. for (int i=1;i<=n;++i)
  30. {
  31. ++top;S[top]=i;ed[top]=i;
  32. while (top>1&&key[S[top]]<key[S[top-1]])
  33. {
  34. --top;
  35. S[top]=merge(S[top],S[top+1]);
  36. if (((ed[top+1]-ed[top])&1)&&((ed[top]-ed[top-1])&1))
  37. S[top]=merge(ls[S[top]],rs[S[top]]);
  38. ed[top]=ed[top+1];
  39. }
  40. }
  41. for (int i=1;i<=top;++i)
  42. for (int j=ed[i-1]+1;j<=ed[i];++j)
  43. ans+=abs(key[j]-key[S[i]]);
  44. printf("%lld\n",ans);
  45. return 0;
  46. }

强行再贴一个洛谷上那道题的代码

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. #define ll long long
  5. inline int gi()
  6. {
  7. int x=0,w=1;char ch=getchar();
  8. while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  9. if (ch=='-') w=0,ch=getchar();
  10. while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
  11. return w?x:-x;
  12. }
  13. const int N = 1e6+5;
  14. int n,key[N],ls[N],rs[N],dis[N],S[N],ed[N],top;
  15. ll ans;
  16. int merge(int A,int B)
  17. {
  18. if (!A||!B) return A|B;
  19. if (key[A]<key[B]) swap(A,B);
  20. rs[A]=merge(rs[A],B);
  21. if (dis[ls[A]]<dis[rs[A]]) swap(ls[A],rs[A]);
  22. dis[A]=dis[rs[A]]+1;
  23. return A;
  24. }
  25. int main()
  26. {
  27. n=gi();
  28. for (int i=1;i<=n;++i) key[i]=gi()-i;
  29. for (int i=1;i<=n;++i)
  30. {
  31. ++top;S[top]=i;ed[top]=i;
  32. while (top>1&&key[S[top]]<key[S[top-1]])
  33. {
  34. --top;
  35. S[top]=merge(S[top],S[top+1]);
  36. if (((ed[top+1]-ed[top])&1)&&((ed[top]-ed[top-1])&1))
  37. S[top]=merge(ls[S[top]],rs[S[top]]);
  38. ed[top]=ed[top+1];
  39. }
  40. }
  41. for (int i=1;i<=top;++i)
  42. for (int j=ed[i-1]+1;j<=ed[i];++j)
  43. ans+=abs(key[j]-key[S[i]]);
  44. printf("%lld\n",ans);
  45. for (int i=1;i<=top;++i)
  46. for (int j=ed[i-1]+1;j<=ed[i];++j)
  47. printf("%d ",key[S[i]]+j);
  48. puts("");return 0;
  49. }

[Luogu4331][Baltic2004]数字序列的更多相关文章

  1. [Baltic2004]数字序列

    原题请见<左偏树的特点及其应用>BY 广东省中山市第一中学 黄源河 题意 给出序列\(a[1...n]\),要求构造序列\(b[1...n]\)使得\(\sum_{i=1}^{n}|a_i ...

  2. 找出数组中最长的连续数字序列(JavaScript实现)

    原始题目: 给定一个无序的整数序列, 找最长的连续数字序列. 例如: 给定[100, 4, 200, 1, 3, 2], 最长的连续数字序列是[1, 2, 3, 4]. 小菜给出的解法: functi ...

  3. 九度OJ 1544 数字序列区间最小值

    题目地址:http://ac.jobdu.com/problem.php?pid=1544 题目描述: 给定一个数字序列,查询任意给定区间内数字的最小值. 输入: 输入包含多组测试用例,每组测试用例的 ...

  4. 【BZOJ】【1049】【HAOI2006】数字序列

    DP 第一问比较水……a[i]-=i 以后就变成最长不下降子序列问题了,第二问这个结论好神奇,考试的时候怎么破?大胆猜想,不用证明?TAT 题解:http://pan.baidu.com/share/ ...

  5. kaggle之数字序列预测

    数字序列预测 Github地址 Kaggle地址 # -*- coding: UTF-8 -*- %matplotlib inline import pandas as pd import strin ...

  6. string 数字序列大小比较

    string 数字序列大小比较 string.compare string a = "022"; string b="1"; 比较结果 '022' < ' ...

  7. codevs 2622 数字序列

    2622 数字序列 提交地址:http://codevs.cn/problem/2622/  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 黄金 Gold     题目描述 De ...

  8. Shell生成数字序列

    转自http://kodango.com/generate-number-sequence-in-shell Shell里怎么输出指定的数字序列: for i in {1..5}; do echo $ ...

  9. 《剑指offer》第四十四题(数字序列中某一位的数字)

    // 面试题44:数字序列中某一位的数字 // 题目:数字以0123456789101112131415…的格式序列化到一个字符序列中.在这 // 个序列中,第5位(从0开始计数)是5,第13位是1, ...

随机推荐

  1. chrome 版本升级到56,报错Your connection is not private NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM

    ubuntu14.04 解决方法: $ sudo apt-get install libnss3-1d ref: http://stackoverflow.com/questions/42085055 ...

  2. 【Java面试题】32 ArrayList和Vector的区别

    1. Vector & ArrayList  相同点: 1.ArrayList和Vector都是继承了相同的父类和实现了相同的接口 2.底层都是数组实现的 3.初始默认长度都为10. 不同点: ...

  3. js中onclick中文参数传输方式

    添加单引号或双引号即可,例: var type = "'"+n.bankCard.type+"'"; var number = "'"+n. ...

  4. c++ const enum #define

    最后的最后,我们略微总结一下:        1.只是声明单一固定值,尽可能采用const.        2.如果是一组固定值,并且互相有关联,则采用enum.        3.不涉及条件编译,只 ...

  5. Tomcat源码学习

    Tomcat源码学习(一) 转自:http://carllgc.blog.ccidnet.com/blog-htm-do-showone-uid-4092-type-blog-itemid-26309 ...

  6. WinSock1.1和WinSock2.0

    网络编程很重要,说到网络编程就不得不提Socket编程. Windows提供了Windows Socket API(简称WSA),WinSock,目前有两个版本:WinSock1.1 and WinS ...

  7. mongodb查询内嵌文档

    mongodb查询内嵌文档   假设有这样一个文档: db.XXX.remove(); db.XXX.insert({"id":1, "members":[{& ...

  8. 九度 1481 Is It A Tree?

    题目 给定一个有向图, 判断其是否是一棵树 要求 (1) 除了根节点外, 每个节点只有唯一的前驱 (2) 从根节点出发, 到任何节点有且只有一条路径 思路 1. 要求(1) 可以通过记录每个节点的前驱 ...

  9. python2.0_s12_day15_django框架的基本使用

    day15本节内容介绍 上节作业讲解(让行进入编辑模式,批量编辑) CSS之特殊内容补充 CSS内容补充之伪类 伪类实例:返回顶部终极版 CSS内容补充之无法被覆盖 jQuery插件 jQuery插件 ...

  10. Serlvet学习笔记之二—不同页面共享数据

    一共有四种方法实现共享页面共享数据 1.cookie 2.sendRedirect 3.session 4.隐藏表单提交(form) 5.ServletContex 1.cookie:服务器在客户端保 ...