[BOI2004]Sequence 数字序列(左偏树)
PS:参考了黄源河的论文《左偏树的特点及其应用》
题目描述:给定一个整数序列\(a_1, a_2, … , a_n\),求一个递增序列\(b_1 < b_2 < … < b_n\),使得序列\(a_i\)和\(b_i\)的各项之差的绝对值之和 \(|a_1 - b_1| + |a_2 - b_2| + … + |a_n - b_n|\) 最小。
不难发现两条性质:
①:若原序列a满足\(a_1 < a_2 < … < a_n\),显然最优情况为\(b_i=a_i\)
②:若原序列a满足\(a_1 > a_2 > … > a_n\),显然最优情况为\(b_{mid}=x\)(x为a中位数)
有了上述的两种情况,不难发现,整个a序列是尤一些单调区间组成。
所以我们可以将原序列a拆成若干个单调区间,最后再将答案合并。
那两段区间的答案怎么合并呢?
我们可以重新找一个中位数来合并即可。
不断的找中位数,不难想到这道题,可是那道题是一个一个加入进堆,而现在我们要解决的是将两个堆合并来找中位数,直接上二叉堆合并复杂度为\(O(n)\),所以不难想到可并堆(这里使用左偏树)。
假设我们已经找到前k个数的最优解,队列中有\(cnt\)段区间,每段区间最优解为\(w_1,w_2,…,w_{cnt}\),现在要加入\(a_{k+1}\),并更新队列。
首先把\(a_{k+1}\)加入队尾,令\(w_{cnt+1}=a_{k+1}\),如果\(w_{cnt}>w_{cnt+1}\),就将最后两个区间合并,并找出新区间的最优解。重复上述过程,直至满足\(w\)单调递增。
注意:题目要求的是一个递增序列b,可以用减下标来实现(即输入时把每个数都减去对应下标,输出时加上),这样就可以将递增序列转化成不下降序列,这样就可以保证每一段区间的序列b不一样了(原本有很多连续一段区间全是中位数,不能保证递增)。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define debug printf("Now is Line : %d\n",__LINE__)
#define file(a) freopen(#a".in","r",stdin);freopen(#a".out","w",stdout)
#define ll long long
#define mod 1000000007
il int read()
{
re int x=0,f=1;re char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
return x*f;
}
#define _ 1000006
int n,dis[_],ch[_][2],cnt;
ll a[_],b[_],ans;
struct node{int root,ls,rs,size,val;}e[_];
il int merge(int x,int y)
{
if(!x||!y) return x+y;
if(a[x]<a[y]||(a[x]==a[y]&&x>y)) swap(x,y);
ch[x][1]=merge(ch[x][1],y);
if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
dis[x]=dis[ch[x][1]]+1;
return x;
}
int main()
{
n=read(); dis[0]=-1;
for(re int i=1;i<=n;++i) a[i]=read()-i;
for(re int i=1;i<=n;++i)
{
e[++cnt]=(node){i,i,i,1,a[i]};
while(cnt>1&&e[cnt].val<e[cnt-1].val)
{
--cnt;
e[cnt].root=merge(e[cnt].root,e[cnt+1].root);
e[cnt].size+=e[cnt+1].size;
e[cnt].rs=e[cnt+1].rs;
while(e[cnt].size*2>e[cnt].rs-e[cnt].ls+2)
{
--e[cnt].size;
e[cnt].root=merge(ch[e[cnt].root][0],ch[e[cnt].root][1]);
}
e[cnt].val=a[e[cnt].root];
}
}
for(re int i=1;i<=cnt;++i)
{
for(re int j=e[i].ls;j<=e[i].rs;++j)
{
b[j]=e[i].val;
ans+=abs(a[j]-b[j]);
}
}
printf("%lld\n",ans);
for(re int i=1;i<=n;++i) printf("%lld ",b[i]+i);
return 0;
}
[BOI2004]Sequence 数字序列(左偏树)的更多相关文章
- 洛谷P4331 [BOI2004] Sequence 数字序列 [左偏树]
题目传送门 数字序列 题目描述 给定一个整数序列 a1,a2,⋅⋅⋅,an ,求出一个递增序列 b1<b2<⋅⋅⋅<bn ,使得序列 ai 和 bi 的各项之差的绝对 ...
- 洛谷$P4331\ [BOI2004]\ Sequence$ 数字序列 左偏树
正解:左偏树 解题报告: 传送门$QwQ$ 开始看到的时候$jio$得长得很像之前做的一个$dp$,,, 但是$dp$那题是说不严格这里是严格? 不难想到我们可以让$a_{i},b_{i}$同时减去$ ...
- Luogu P4331 [BOI2004]Sequence 数字序列 (左偏树论文题)
清晰明了%%% Fairycastle的博客 个人习惯把size什么的存在左偏树结点内,这样在外面好写,在里面就是模板(只用修改update). 可以对比一下代码(好像也差不多-) MY CODE # ...
- [BOI2004]Sequence 数字序列
Description: Hint: \(n<=10^5\) Solution: 首先考虑b不严格递增时的做法 发现当\(a[i]\)递增时\(b[i]\)直接取\(a[i]\)即可,否则此时需 ...
- luoguP4331 [BOI2004]Sequence 数字序列
题意 大力猜结论. 首先将所有\(a_i\)变为\(a_i-i\),之后求不严格递增的\(b_i\),显然答案不变,最后\(b_i\)加上\(i\)即可. 考虑两种特殊情况: 1.\(a[]\)是递增 ...
- P4331 [BOI2004]Sequence 数字序列 (左偏树)
[题目链接] https://www.luogu.org/problemnew/show/P4331 题目描述 给定一个整数序列\(a_1, a_2, ··· , a_n,\)求出一个递增序列\(b_ ...
- 洛谷P4331 [BOI2004]Sequence 数字序列(左偏树)
传送门 感觉……不是很看得懂题解在说什么? 我们先把原数列$a_i-=i$,那么本来要求递增序列,现在只需要求一个非严格递增的就行了(可以看做最后每个$b_i+=i$,那么非严格递增会变为递增) 如果 ...
- 2021.08.01 P4311 数字序列(左偏树)
2021.08.01 P4311 数字序列(左偏树) [P4331 BalticOI 2004]Sequence 数字序列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1 ...
- 黄源河《左偏树的应用》——数字序列(Baltic 2004)
这道题哪里都找不到. [问题描述] 给定一个整数序列a1, a2, … , an,求一个不下降序列b1 ≤ b2 ≤ … ≤ bn,使得数列{ai}和{bi}的各项之差的绝对值之和 |a1 - b1| ...
随机推荐
- Grafana 利用Grafana Variables变量配置快速切换不同主机的图表数据展示
用Grafana Variables变量配置快速切换不同主机的图表数据展示 by:授客 QQ:1033553122 测试环境 需求描述 操作步骤 结果展示 测试环境 influxdb-1.5.2. ...
- Android BroadcastReceiver 接收收到短信的广播
一.知识介绍 1.broadcastReceiver是广播接受者,四大组件之一. 2.Android中内置了很多系统级别的广播,可以在应用程序中得到各种系统的状态信息. 3.使用场景: ①当手机没有电 ...
- Netty学习笔记(三) 自定义编码器
编写一个网络应用程序需要实现某种编解码器,编解码器的作用就是讲原始字节数据与自定义的消息对象进行互转.网络中都是以字节码的数据形式来传输数据的,服务器编码数据后发送到客户端,客户端需要对数据进行解码, ...
- DataSnap 多层返回数据集分析FireDAC JSON
采用服务器返回数据,一种是返回字符串数据例如JSON,跨平台跨语言,任何语言调用都支持兼容,类似WEBService. 第二种是紧密结合c++builder语言,传输DataSet,可以是Client ...
- 彻底删除mysql服务(清理注册表)
由于安装某个项目的执行文件,提示要卸载MySQL以便它自身MySQL安装,然后我禁用了MYSQL服务,再把这个文件夹删除后,发现还是提示请卸载MYSQL服务. 解决步骤: 1.以管理员身份运行命令提示 ...
- 网络编程中TCP基础巩固以及Linux打开的文件过多文件句柄的总结
1.TCP连接(短链接和长连接) 什么是TCP连接?TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议. 当网络通信 ...
- C# 不用递归,获取无限层级数据
对象属性 public class ResList { public int ID { get; set; } public List<ResList> Child { get; set; ...
- AngularJS学习之旅—AngularJS 服务(八)
1.AngularJS 服务(Service) AngularJS 中你可以创建自己的服务,或使用内建服务.2.什么是服务? 在 AngularJS 中,服务是一个函数或对象,可在你的 Angular ...
- log4j控制指定包下的日志
最近观察日志发现如下两个问题: 1.项目用的是springboot项目,整合了rabbitmq,项目启动后,会自动监控rabbitmq谅解是否正常,导致控制台一直输出监控日志,此时就想阻止该类日志输出 ...
- SQL SUM() 函数
SUM() 函数 SUM 函数返回数值列的总数(总额). SQL SUM() 语法 SELECT SUM(column_name) FROM table_name SQL SUM() 实例 我们拥有下 ...