首先枚举出所有可能成为区间最小差值的点对$(j,i)$。

枚举每个位置作为右端点$i$,假设$a[j]>a[i]$。

找到第一个这样的$j$,那么可以将下一个$a[j]$的范围缩小到$(a[i],\frac{a[i]+a[j]}{2})$。这是因为在这之外的数要么没有$j$优,要么会被$j$考虑到。

利用可持久化线段树可以很容易地找到下一个$j$的位置,最多$O(n\log n)$个点对,时间复杂度$O(n\log^2n)$。

接下来的问题等价于选择$k$条不相交线段,使得价值和最小。

将线段按左端点从小到大排序,设$f[i][j]$表示考虑前$i$条线段,选择了$j$条线段的最优价值,可以通过双指针优化到$O(kn\log n)$。

注意到$f[all][j]$是个凸函数,故可以二分斜率$mid$来切它,具体体现为每选一条线段,价值就多加$mid$。

那么随着$mid$的增大,最优解中选择的线段数目会越来越少。

二分找到最优解中线段数目最接近$k$的$mid$即可。

时间复杂度$O(n\log^2n)$。

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. const int N=50010,M=N*18;
  5. int n,m,K,i,a[N],tot,T[N],l[M],r[M],v[M],tmp,ans,s[N],g[M*2];double L,R,MID,f[M*2];
  6. struct E{int l,r,v;E(){}E(int _l,int _r,int _v){l=_l,r=_r,v=_v;}}e[M*2];
  7. inline bool cmp(const E&a,const E&b){return a.l<b.l;}
  8. inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
  9. int ins(int x,int a,int b,int c,int p){
  10. int y=++tot;
  11. v[y]=p;
  12. if(a==b)return y;
  13. int mid=(a+b)>>1;
  14. if(c<=mid)l[y]=ins(l[x],a,mid,c,p),r[y]=r[x];
  15. else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c,p);
  16. return y;
  17. }
  18. void ask(int x,int a,int b,int c,int d){
  19. if(!x)return;
  20. if(c<=a&&b<=d){
  21. if(v[x]>tmp)tmp=v[x];
  22. return;
  23. }
  24. int mid=(a+b)>>1;
  25. if(c<=mid)ask(l[x],a,mid,c,d);
  26. if(d>mid)ask(r[x],mid+1,b,c,d);
  27. }
  28. inline void findbigger(int x){
  29. int l=a[x]+1,r=n,t=x-1;
  30. while(l<=r&&t){
  31. tmp=0;
  32. ask(T[t],1,n,l,r);
  33. if(!tmp)return;
  34. t=tmp;
  35. e[++m]=E(t,x,a[t]-a[x]);
  36. r=(a[x]+a[t--]-1)>>1;
  37. }
  38. }
  39. inline void findsmaller(int x){
  40. int l=1,r=a[x]-1,t=x-1;
  41. while(l<=r&&t){
  42. tmp=0;
  43. ask(T[t],1,n,l,r);
  44. if(!tmp)return;
  45. t=tmp;
  46. e[++m]=E(t,x,a[x]-a[t]);
  47. l=(a[x]+a[t--]+2)>>1;
  48. }
  49. }
  50. inline void up(int&x,int y){if(f[x]>f[y])x=y;}
  51. inline void cal(){
  52. int i,j;
  53. for(i=1;i<=n;i++)s[i]=0;
  54. for(i=1,j=ans=0;i<=m;i++){
  55. while(j+1<e[i].l){
  56. j++;
  57. up(s[j],s[j-1]);
  58. }
  59. f[i]=f[s[j]]+e[i].v+MID;
  60. g[i]=g[s[j]]+1;
  61. up(s[e[i].r],i);
  62. up(ans,i);
  63. }
  64. }
  65. int main(){
  66. read(n),read(K);
  67. for(i=1;i<=n;i++)read(a[i]),T[i]=ins(T[i-1],1,n,a[i],i);
  68. for(i=1;i<=n;i++)findbigger(i),findsmaller(i);
  69. sort(e+1,e+m+1,cmp);
  70. L=-1e9,R=1e9;
  71. for(int _=80;_;_--){
  72. MID=(L+R)/2;
  73. cal();
  74. if(g[ans]==K)break;
  75. if(g[ans]<K)R=MID;else L=MID;
  76. }
  77. return printf("%.0f",f[ans]-MID*K),0;
  78. }

  

BZOJ4167 : 永远的竹笋采摘的更多相关文章

  1. 【BZOJ4167】永远的竹笋采摘 分块+树状数组

    [BZOJ4167]永远的竹笋采摘 题解:我们考虑有多少点对(a,b)满足a与b的差值是[a,b]中最小的.以为是随机数据,这样的点对数目可能很少,实测是O(n)级别的,那么我们已知了有这么多可能对答 ...

  2. BZOJ 4167: 永远的竹笋采摘

    首先同BZOJ5052 \(O(n \log n \log v)\) 求出所有点对 现在变成选出 \(k\) 条不相交的线段使得权值最小 可用前缀min优化dp \(O(nk)\) 解决 还是太慢,考 ...

  3. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  4. 一段良好的程序永远不应该发生panic异常

    panic来自被调函数的信号,表示发生了某个已知的bug.一段良好的程序永远不应该发生panic异常 对于大部分程序而言,永远无法保证能够成功运行,因为错误原因往往超出程序员的控制范围.任何进行io操 ...

  5. GPIB:永远不会被淘汰 (转载)

    发布时间:2014-07-02    来源:www.china-igbt.com 1994年5月出版的<测试与测量世界>中刊登了我冒险撰写的一篇名为<GPIB,时刻保持警惕>的 ...

  6. DIV+CSS:页脚永远保持在页面底部

    页脚永远保持在页面底部 有时候,我们用CSS创建一个高度自适应布局,如何保证页脚(footer)在内容不超过一屏的情况下始终保持在布局最下方是一个比较头疼的事.我看过一些利用绝对定位的例子,但总感觉不 ...

  7. 假如现在有一堆长度大于3小于9的电话号码,用座机呼叫,如果出现这样的号码【123和12345】那么12345将永远不会被拨出,因为拨到123的时候电话已经呼出了,试写一个函数输出所有不能被呼出的电话号码(java实现)

    解题: 假如现在有一堆长度大于3小于9的电话号码,用座机呼叫,如果出现这样的号码[123和12345]那么12345将永远不会被拨出,因为拨到123的时候电话已经呼出了,试写一个函数输出所有不能被呼出 ...

  8. Ubuntu为何永远绝对的免费?

    Ubuntu(发行版)是一个Linux大家族,而且个个都称得上是软件精品.所谓“绝对”就是没有任何条件.不受任何限制的意思.那么,Ubuntu怎么可能是永远绝对的免费?难道这不是蛊惑人心的宣传.不能兑 ...

  9. 永远不要修改arguments对象

    案例复现 var obj = { plus: function(arg0, arg1) { return arg0 + arg1; } }; function callMethod(context, ...

随机推荐

  1. 论文阅读笔记十二:Encoder-Decoder with Atrous Separable Convolution for Semantic Image Segmentation(DeepLabv3+)(CVPR2018)

    论文链接:https://arxiv.org/abs/1802.02611 tensorflow 官方实现: https: //github.com/tensorflow/models/tree/ma ...

  2. poj2398

    题解: 计算几何入门题 对每个二分最近的在它右边的杆子 如何判断一个杆子在它右边呢 计算机判断这些要更善于利用点积和叉积 如果叉积为正代表在顺时针方向叉积为负在逆时针 发现要在struct里面重载运算 ...

  3. linux下几个常用软件

    Ubuntu 软件包地址 https://packages.ubuntu.com/ 一. 字体 不管是雅黑还是宋体,从windows cp过来后, 直接双击打开并安装 二. Meld 可视的diff和 ...

  4. error: Unable to find vcvarsall.bat

    http://www.crifan.com/python_mmseg_error_unable_to_find_vcvarsall_bat/ [已解决]安装Python模块mmseg出错:error: ...

  5. Nginx Java 日志切割脚本

    Nginx日志切割脚本: #!/bin/bash ########################################################################### ...

  6. flink的流处理特性

    flink的流处理特性: 支持高吞吐.低延迟.高性能的流处理 支持带有事件时间的窗口(Window)操作 支持有状态计算的Exactly-once语义 支持高度灵活的窗口(Window)操作,支持基于 ...

  7. Fiddler的安装与使用

    Fiddler是位于客户端和服务器端之间的代理,也是目前最常用的抓包工具之一 .它能够记录客户端和服务器之间的所有 请求,可以针对特定的请求,分析请求数据.设置断点.调试web应用.修改请求的数据,甚 ...

  8. AtCoder Regular Contest 100 (ARC100) E - Or Plus Max 其他

    原文链接https://www.cnblogs.com/zhouzhendong/p/9251448.html 题目传送门 - ARC100E 题意 给定一个正整数 $n(n\leq 18)$. 然后 ...

  9. java生成二维码以及读取案例

    今天有时间把二维码这块看了一下,方法有几种,我只是简单的看了一下  google  的  zxing! 很简单的一个,比较适合刚刚学习java的小伙伴哦!也比较适合以前没有接触过和感兴趣的的小伙伴,o ...

  10. spring框架等web程序在tomcat下的启动顺序

    http://www.cnblogs.com/panxuejun/p/5847774.html