题面描述

给定整数数组$a_1,a_2,a_3...a_n$,求递增数组$b_1,b_2,b_3...b_n$

使得$|a_1 - b_1| + |a_2 - b_2| + ... + |a_n - b_n|$最大

吐槽:

这道题不是人能想出来的,太神了

很有收获?$or\; not\;?$

题解:

考虑$b$数组严格递增这个条件过于苛刻,期望$b$数组不严格递增

那么,由于$b_1 < b_2 < ... < b_n$,有$b_1 - 1 \leq b_2 - 2 ... \leq b_n - n$

我们不妨考虑新的$b'_i = b_i - i$

在$b'_i$对$a'_i = a_i - i$取到最优时,$b_i$同时对$a_i$取到最优

这时,$b‘_i$就可以相等了

两个性质

1. 对于$a'_1 \leq a'_2 \leq ... \leq a'_n$,我们取$b'i = a'i$最优

2. 对于$a'_1 \geq a'_2 \geq ... \geq a'_n$,我们取$b'i$为中位数最优

并且由于$b'_i$相等,$a'_1, a'_2...a'_n$可以任意的排列

因此,我们不妨假设已经处理好了前$i - 1$个数,正要加入第$i$个数

我们假设维护出来的$b'_i$相同的并成一个区间,$b'_i$取这个区间的中位数

对于$a'_i > b'_{i - 1}$,取$b'_i = a'_i$时,相等于递增序列

否则$a'_i < b'_{i - 1}$,我们把$i$并入$b'_{i - 1}$,得到新的中位数(因为顺序任意,所以怎么合都没问题),并继续检查

那么,我们要做的事其实就是

1. 快速合并两个区间中的数

2. 确定出区间中的中位数

左偏树就是不错的选择

复杂度$O(n\log n)$

#include <cstdio>
#include <cmath>
#include <iostream>
#define sid 1000500
#define ll long long
#define ri register int
#define ls(o) t[o].ls
#define rs(o) t[o].rs
using namespace std; char RR[];
#define isdigit(u) (u >= '0' && u <= '9')
extern inline char gc() {
static char *S = RR + , *T = RR + ;
if(S == T) S = RR, fread(RR, , , stdin);
return *S ++;
}
inline int read() {
int o = , w = ; char c = gc();
while(!isdigit(c)) {if(c == '-') w = -; c = gc();}
while(isdigit(c)) o = o * + c - '', c = gc();
return o * w;
} int n, cnt;
int rt[sid], ld[sid], rd[sid], a[sid];
struct reHeap {
int ls, rs, sz, npl, key;
} t[sid]; inline void update(int o) {
t[o].sz = t[ls(o)].sz + t[rs(o)].sz + ;
t[o].npl = t[rs(o)].npl + ;
} int merge(int x, int y) {
if(!x || !y) return x + y;
if(t[x].key < t[y].key) swap(x, y);
rs(x) = merge(rs(x), y);
if(t[rs(x)].npl > t[ls(x)].npl) swap(ls(x), rs(x));
update(x); return x;
} int main() {
n = read();
for(ri i = ; i <= n; i ++) {
ld[++ cnt] = rd[cnt] = rt[cnt] = i;
a[i] = t[i].key = read() - i; t[i].sz = ;
while(cnt > && t[rt[cnt]].key < t[rt[cnt - ]].key) {
cnt --; rd[cnt] = rd[cnt + ];
rt[cnt] = merge(rt[cnt], rt[cnt + ]);
while(t[rt[cnt]].sz * > rd[cnt] - ld[cnt] + )
rt[cnt] = merge(ls(rt[cnt]), rs(rt[cnt]));
}
}
ll ans = ;
for(ri i = ; i <= cnt; i ++)
for(ri j = ld[i]; j <= rd[i]; j ++)
ans += abs(t[rt[i]].key - a[j]);
printf("%lld\n", ans);
for(ri i = ; i <= cnt; i ++)
for(ri j = ld[i]; j <= rd[i]; j ++)
printf("%d ", t[rt[i]].key + j);
return ;
}

[BOI2004]Sequence的更多相关文章

  1. 洛谷P4331 [BOI2004] Sequence 数字序列 [左偏树]

    题目传送门 数字序列 题目描述 给定一个整数序列 a1​,a2​,⋅⋅⋅,an​ ,求出一个递增序列 b1​<b2​<⋅⋅⋅<bn​ ,使得序列 ai​ 和 bi​ 的各项之差的绝对 ...

  2. [BOI2004]Sequence 数字序列(左偏树)

    PS:参考了黄源河的论文<左偏树的特点及其应用> 题目描述:给定一个整数序列\(a_1, a_2, - , a_n\),求一个递增序列\(b_1 < b_2 < - < ...

  3. [BOI2004]Sequence 数字序列

    Description: Hint: \(n<=10^5\) Solution: 首先考虑b不严格递增时的做法 发现当\(a[i]\)递增时\(b[i]\)直接取\(a[i]\)即可,否则此时需 ...

  4. P4331 [BOI2004]Sequence 数字序列 (左偏树)

    [题目链接] https://www.luogu.org/problemnew/show/P4331 题目描述 给定一个整数序列\(a_1, a_2, ··· , a_n,\)求出一个递增序列\(b_ ...

  5. 洛谷P4331 [BOI2004]Sequence 数字序列(左偏树)

    传送门 感觉……不是很看得懂题解在说什么? 我们先把原数列$a_i-=i$,那么本来要求递增序列,现在只需要求一个非严格递增的就行了(可以看做最后每个$b_i+=i$,那么非严格递增会变为递增) 如果 ...

  6. luoguP4331 [BOI2004]Sequence 数字序列

    题意 大力猜结论. 首先将所有\(a_i\)变为\(a_i-i\),之后求不严格递增的\(b_i\),显然答案不变,最后\(b_i\)加上\(i\)即可. 考虑两种特殊情况: 1.\(a[]\)是递增 ...

  7. Luogu P4331 [BOI2004]Sequence 数字序列 (左偏树论文题)

    清晰明了%%% Fairycastle的博客 个人习惯把size什么的存在左偏树结点内,这样在外面好写,在里面就是模板(只用修改update). 可以对比一下代码(好像也差不多-) MY CODE # ...

  8. 洛谷P4331[BOI2004] sequence

    博客复活? 这个题很模板啊.随便上个左偏树.之前第一遍写对了.然后今天翻出来又写了一遍发现了一个奇奇怪怪的问题. 对比如下 上面的是AC 下面的WA 真的是一个很蠢的问题...你TM堆顶都弹出来了,堆 ...

  9. 洛谷$P4331\ [BOI2004]\ Sequence$ 数字序列 左偏树

    正解:左偏树 解题报告: 传送门$QwQ$ 开始看到的时候$jio$得长得很像之前做的一个$dp$,,, 但是$dp$那题是说不严格这里是严格? 不难想到我们可以让$a_{i},b_{i}$同时减去$ ...

随机推荐

  1. 【NOIP2013提高组T3】加分二叉树

    题目描述 设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号.每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都 ...

  2. 【leetcode 简单】第四十九题 颠倒二进制位

    颠倒给定的 32 位无符号整数的二进制位. 示例: 输入: 43261596 输出: 964176192 解释: 43261596 的二进制表示形式为 000000101001010000011110 ...

  3. redis笔记之两种持久化备份方式(RDB & AOF)

    Redis支持的两种持久化备份方式(RDB & AOF) redis支持两种持久化方式,一种是RDB,一种是AOF. RDB是根据指定的规则定时将内存中的数据备份到硬盘上,AOF是在每次执行命 ...

  4. PHP提取url

    <?php $str = parse_url('http://localhost/?id=2&cd=2', PHP_URL_QUERY); ECHO $str; parse_str($s ...

  5. HOJ 1108

    题目链接:HOJ-1108 题意为给定N和M,找出最小的K,使得K个N组成的数能被M整除.比如对于n=2,m=11,则k=2. 思路是抽屉原理,K个N组成的数modM的值最多只有M个. 具体看代码: ...

  6. 设计模式之笔记--解释器模式(Interpreter)

    解释器模式(Interpreter) 定义 解释器模式(Interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 类图 描述 Expr ...

  7. C/C++——[05] 函数

    函数是 C/C++语言中的一种程序组件单位.一个函数通常代表了一种数据处理的功能,由函数体和函数原型两部分组成.函数原型为这个数据处理功能指定一个标识符号(函数的名称).说明被处理数据的组成及其类型. ...

  8. 使用非root用户启动tomcat

    以下操作均为以root用户运行1.添加tomcat用户组 /usr/sbin/groupadd tomcat 2.添加tomcat用户,并限制登录 /usr/sbin/useradd -s /bin/ ...

  9. 登陆记录utmp wtmp

    /var/log/wtmp文件的作用     /var/log/wtmp也是一个二进制文件,记录每个用户的登录次数和持续时间等信息.   查看方法:   可以用last命令输出当中内容: debian ...

  10. POJ 3186Treats for the Cows(区间DP)

    题目链接:http://poj.org/problem?id=3186 题目大意:给出的一系列的数字,可以看成一个双向队列,每次只能从队首或者队尾出队,第n个出队就拿这个数乘以n,最后将和加起来,求最 ...