洛谷题面传送门

u1s1 在我完成这篇题解之前,全网总共两篇题解,一篇使用的平衡树,一篇使用的就是这篇题解讲解的这个做法,但特判掉了一个点,把特判去掉在 BZOJ 上会 WA 一个点。

两篇题解都异常简略,前一篇题解甚至只有代码没有说明,所以这里我来写篇比较详细题解造福人类了(大雾

建议没做过这题的同学先看看这道题,看题解区第一个做法,对这题有比较大的启发。

注:下文中分别用 \(a,b,l,r\) 代替题面中的 \(X,Y,A,B\)。

首先关于这题咱们可以想到一个非常 naive 的 DP,\(dp_{i,j}\) 表示考虑到前两个数,\(b_i=j\) 的 \(\sum\limits_{k=1}^i|a_k-b_k|\)。那么显然有 DP 转移 \(dp_{i,j}=\min\limits_{k=l}^rdp_{i-1,j-k}+|a_i-j|\)。一脸不好直接维护的样子。不过注意到绝对值函数是一个下凸函数,因此我们猜测对于一个固定的 \(i\),\(dp_{i,j}\) 随 \(j\)​ 的增大也是一个下凸函数,事实也的确如此,证明大概可以归纳,可能需要一些分类讨论,这里不再赘述,留给读者自己思考。

我们还可以注意到,每一轮中每条直线斜率变化的绝对值最多为 \(1\)​​,也就是说任意时刻,下凸壳中直线斜率绝对值的最大值顶多为 \(n\)​​,因此我们考虑维护 \(2n+2\)​​ 个分界点的横坐标,具体来说,记 \(x_i\)​​ 为第 \(i\)​​ 个分界点,那么以凸包上横坐标分别为 \(x_i,x_{i+1}\)​​ 的点组成线段刚好是凸包上斜率为 \(i-n-2\)​​ 的直线,当然也有可能 \(x_i=x_{i+1}\)​​,此时凸包上不存在斜率为 \(i-n-2\)(说白了就是记录凸包拐点的横坐标)。

接下来考虑加入一个 \(a_i\)​​ 后会对凸包产生怎样的影响。我们考虑将每一轮转移的过程分成两部分:\(dp_{i,j}=\min\limits_{k=l}^rdp_{i-1,j-k}\)​ 和 \(dp_{i,j}:=dp_{i,j}+|a_i-j|\)​,首先对于第一部分而言,显然在凸包上存在一些分界点,满足分界点前面单调不增,分界点之后单调不降,不难发现这些分界点组成的集合就是斜率为 \(0\)​ 的直线。假设斜率为 \(0\)​ 的直线的两个端点横坐标为 \(u,v(u,v)\)​,那么不难发现对于 \(j\le u+l\),由于 \(u\) 前面单调递减,因此我们肯定会尽量选择 \(j\) 与接近的点转移,即 \(dp_{i,j-l}\),因此我们可以得到,进行第一步操作后,凸包上 \(u\) 前面的点都会向右平移 \(l\) 格,同理在 \(v+r\) 后面的点 \(j\),我们肯定会尽量选离 \(j\) 远的点的即 \(j-r\),也就是说 \(v\)​ 后面的点肯定会向右平移 \(r\) 格,至于中间的部分……那显然还是一条水平的直线咯(

第二部分就相对比较简单了,不难发现 \(f(x)=|a_i-x|\) 在 \((-\infty,a_i)\) 中是斜率为 \(-1\) 的直线,\((a_i,\infty)\)​ 中是斜率为 \(1\) 的直线,因此 \(a_i\)​ 前面的部分的直线的斜率会减 \(1\),后面的部分斜率会加 \(1\)。这样我们可以看作是在 \(a_i\) 处插入了两个断点。

考虑怎样维护这个东西,我们开两个堆 \(L,R\) 分别存储斜率为 \(0\) 的直线前面和后面的断点,那么时刻 \(i\) 时显然 \(L\) 应当为存储的是最小的 \(i\) 个断点,\(R\) 应当存储最大的 \(i\) 个断点,但有时并不一定真的存储的就是最小/最大的 \(i\) 个断点,这时候我们就要进行调整,具体方法就是取出 \(L\) 中最大的元素 \(x\) 和最小的元素 \(y\),如果 \(x>y\) 就将 \(x\) 插入 \(R\),\(y\) 插入 \(L\),否则 break。还有一个问题就是如何处理坐标平移,具体方法就在 \(i\) 时刻是将 \(x\) 插入 \(L\) 时我们不插入 \(x\) 本身,而是插入 \(x-(i-1)l\),这样在 \(i’\) 时刻这个点真正的坐标就是 \(x+i’l\),不难发现这里用了差分的思想,在统计每个点有多少个时刻满足 xxxx 条件时也用到了类似的思想。

时间复杂度 \(n\log n\)

注意加一些特判,否则在 BZOJ 上会 WA 一个点,进而取得 \(0\) 分的好成绩(London Fog

const int MAXN=5e5;
int n,mx,l,r,a[MAXN+5],b[MAXN+5];ll ext=0;
priority_queue<ll> L;
priority_queue<ll,vector<ll>,greater<ll> > R;
//void prt(auto q){
// while(!q.empty()) printf("%d ",q.top()),q.pop();
// printf("\n");
//}
int main(){
scanf("%d%d%d%d",&n,&mx,&l,&r);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]<1ll*(i-1)*l+1){
ext+=abs(a[i]-(1ll*(i-1)*l+1));
a[i]=1ll*(i-1)*l+1;
}
}
for(int i=1;i<=n;i++){
L.push(a[i]-1ll*(i-1)*l);
R.push(a[i]-1ll*(i-1)*r);
while(1){
ll x=L.top();x+=1ll*(i-1)*l;
ll y=R.top();y+=1ll*(i-1)*r;
// printf("%lld %lld\n",x,y);
if(x<=y) break;L.pop();R.pop();
L.push(y-1ll*(i-1)*l);R.push(x-1ll*(i-1)*r);
} b[i]=L.top()+1ll*(i-1)*l;
// prt(L);prt(R);
} ll res=0;chkmin(b[n],mx);
chkmax(b[n],1ll*l*(n-1)+1);//be careful
for(int i=n-1;i;i--){
if(b[i]<b[i+1]-r) b[i]=b[i+1]-r;
if(b[i]>b[i+1]-l) b[i]=b[i+1]-l;
}
// if(n==8888) for(int i=1;i<=n;i++) printf("%d%c",b[i]," \n"[i==n]);
for(int i=1;i<=n;i++) res+=abs(a[i]-b[i]);
printf("%lld\n",res+ext);
return 0;
}

洛谷 P4272 - [CTSC2009]序列变换(堆)的更多相关文章

  1. 【洛谷P1483】序列变换

    题目大意:给定一个长度为 N 的序列,有 M 个操作,支持将下标为 x 的倍数的数都加上 y,查询下标为 i 的元素的值. 题解:由于查询操作很少,相对的,修改操作很多.若直接模拟修改操作,即:枚举倍 ...

  2. 洛谷 P1628 合并序列

    洛谷 P1628 合并序列 题目传送门 题目描述 有N个单词和字符串T,按字典序输出以字符串T为前缀的所有单词. 输入格式 输入文件第一行包含一个正整数N: 接下来N行,每行一个单词,长度不超过100 ...

  3. 洛谷 P5470 - [NOI2019] 序列(反悔贪心)

    洛谷题面传送门 好几天没写题解了,写篇题解意思一下(大雾 考虑反悔贪心,首先我们考虑取出 \(a,b\) 序列中最大的 \(k\) 个数,但这样并不一定满足交集 \(\ge L\) 的限制,因此我们需 ...

  4. [洛谷P1032] 字串变换

    洛谷题目链接:字串变换 题目描述 已知有两个字串 A, B 及一组字串变换的规则(至多6个规则): A1 -> B1 A2 -> B2 规则的含义为:在 A$中的子串 A1 可以变换为 B ...

  5. BZOJ 1500 洛谷2042维护序列题解

    BZ链接 洛谷链接 这道题真是丧心病狂.... 应该很容易就可以看出做法,但是写代码写的....... 思路很简单,用一个平衡树维护一下所有的操作就好了,重点讲解一下代码的细节 首先如果按照常规写法的 ...

  6. 【洛谷 P1631】 序列合并 (堆)

    题目链接 直接暴力搞是\(n\)方的复杂度.\(n^2\)个数选\(n\)个最小的,容易想到堆. 我们堆里记录两个信息:到\(A\)数组哪个位置了,到\(B\)数组哪个位置了, 我直接把这两个信息存在 ...

  7. 【洛谷P1963】[NOI2009]变换序列(二分图匹配)

    传送门 题意: 现有一个\(0\)到\(n-1\)的排列\(T\),定义距离\(D(x,y)=min\{|x-y|,N-|x-y|\}\). 现在给出\(D(i, T_i)\),输出字典序最小的符合条 ...

  8. 洛谷P4165 [SCOI2007]组队(排序 堆)

    题意 题目链接 Sol 跟我一起大喊:n方过百万,暴力踩标算! 一个很显然的思路是枚举\(H, S\)的最小值算,复杂度\(O(n^3)\) 我们可以把式子整理一下,变成 \[A H_i + B S_ ...

  9. 洛谷P3378 【模板】堆

    P3378 [模板]堆 160通过 275提交 题目提供者HansBug 标签 难度普及- 提交  讨论  题解 最新讨论 经实际测试 堆的数组开3000- 题目有个问题 为什么这个按课本堆标准打的- ...

随机推荐

  1. 【c++ Prime 学习笔记】第12章 动态内存

    对象的生存期: 全局对象:程序启动时创建,程序结束时销毁 局部static对象:第一次使用前创建,程序结束时销毁 局部自动对象:定义时创建,离开定义所在程序块时销毁 动态对象:生存期由程序控制,在显式 ...

  2. 全连接层dense作用

    参考来源

  3. 常见SOC启动流程分析

    本文以s5pv210这款SOC为例,分析了其启动流程 在s5pv210的SOC内部,存在着一个内部的ROM和一个内部的RAM 这个内部的ROM叫做 IROM,它是norflash的一种.其不同于板子上 ...

  4. 一张图彻底搞懂Spring循环依赖

    1 什么是循环依赖? 如下图所示: BeanA类依赖了BeanB类,同时BeanB类又依赖了BeanA类.这种依赖关系形成了一个闭环,我们把这种依赖关系就称之为循环依赖.同理,再如下图的情况: 上图中 ...

  5. 并发编程从零开始(十一)-Atomic类

    并发编程从零开始(十一)-Atomic类 7 Atomic类 7.1 AtomicInteger和AtomicLong 如下面代码所示,对于一个整数的加减操作,要保证线程安全,需要加锁,也就是加syn ...

  6. stop: Job failed while stopping start: Job is already running: networking eth0 not configured

    再给ubuntu系统重启网络服务的时候出现失败,"stop: Job failed while stopping start: Job is already running: network ...

  7. python 模块 hashlib(提供多个不同的加密算法)

    hashlib是涉及安全散列和消息摘要,提供多个不同的加密算法借口,如SHA1.SHA224.SHA256.SHA384.SHA512.MD5等. import hashlib m = hashlib ...

  8. Typora和PicGo-Core搭配使用

    作用:快速上传图片并获取图片 URL 链接的工具,图片存放到Gitee仓库中,在博客网站发布时不必担心图片转存失败问题 Gitee 创建一个新仓库 生成一个新令牌 生成后只显示一次,请妥善保管 Pic ...

  9. 记一次 php-fpm 连接 nginx 的错误。

    环境: docker 中 centos 镜像下 yum 安装的php,nginx. [root@lnmp1 /]# php -v PHP 7.2.11 (cli) (built: Oct 9 2018 ...

  10. Xtrabackup 全量备份脚本

    #!/bin/bash #备份文件的名字为当前主机的IP地址+tar.gz,例如172.16.103.1.tar.gz,且每次备份成功之后都会清空本地的备份目录. #相关目录 mkdir -p /xt ...