Description

给定一个序列\(t_1,t_2,\cdots,t_n\),求一个递增序列\(z_1<z_2<...<z_n\),

使得 \(R=|t_1−z_1|+|t_2−z_2|+\cdots +|t_n−z_n|\) 的值最小。求\(R\)

Analysis

1.转化

\(z_1<z_2<...<z_n\)的小于号不爽

转化成\(z_1\le z_2\le...\le z_n\)

我们令\(i<j\), 根据条件我们有\(z_j-z_i\ge j-i\)

移一下项则\(z_i-i \le z_j-j\)

我们令\(x_i=t_i-i\),\(y_i=z_i-i\)

用\(x,y\)相减是等价的, 且转化成了\(y_1\le y_2\le...\le y_n\)

后面我们用\(x,y\)代替\(t,z\)

2.尝试简单化的题目

假如x单调递增,那么\(x_i=y_i\)

假如x单调递减呢,\(y_1=y_2=\cdots=y_n=\)x中位数

注:单调递增可以表示为多个单调递减

证明:

假如有条件\(y_1=y_2=\cdots =y_n\), 这个证明不难

现在稍微加一步

①设\(y_i\)变小,则\(y_1...y_{i-1}\)都变小

若\(i<mid\),R显然变大

若\(i>mid\),R变大的点数比变小的点数要多

②设\(y_i\)变大,同理

Solution

对于每个点i一开始属于块i,块中答案\(ans_i=x_i\)

从前往后扫,维护单调队列, 出现y变小的时候退栈

将两个区间合并,合并后区间的ans变为两块一起的中位数

一直合并, 知道上一个区间的y比当前区间的y小

证明:

首先,合并过的区间一定含有至少一个长度大于1的单调减区间

且一开始,合并过的区间里每个区间都只有一个单调减区间

现在我们要证明的就是两个(多个)单调减区间拼在一起的最优答案也是中位数

跟前面的证明是类似的,如图(绿线辅助线,黑线表示两个单调减区间)

(考虑移动ans那条线)

正确性

归纳, 初始答案为\(y_1=x_1\)

考虑当前加入\(x_i\)

如果\(y_{i-1}\le x_i\), 显然, 直接令\(y_i = x_i\)是最优的

当出现\(y_{i-1}\gt x_i\)时, 通过合并操作可以使得答案变优, \(y\)最大值变小

Code

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
using namespace std;
typedef long long LL;
const int M=1000007;
inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=1;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
} int n;
int x[M];
struct node{
int l,r;
int rt;
node(int ll=0,int rr=0,int __=0){
l=ll;r=rr;
rt=__;
}
}que[M];
int tt; int val[M];
int dist[M];
int sz[M];
int lc[M],rc[M]; int merge(int x,int y){
if(!x) return y;
if(!y) return x;
if(val[x]<val[y]) swap(x,y);
rc[x]=merge(rc[x],y);
if(dist[rc[x]]>dist[lc[x]]) swap(lc[x],rc[x]);
dist[x]=dist[rc[x]]+1;
sz[x]=sz[lc[x]]+sz[rc[x]]+1;
return x;//*****
} void pop(int &x){
x=merge(lc[x],rc[x]);
} int main(){
int i,j;
n=rd();
for(i=1;i<=n;i++) x[i]=rd()-i;
for(i=1;i<=n;i++){
que[++tt]=node(i,i,i);
val[i]=x[i];
dist[i]=sz[i]=1;
while(tt>1&&val[que[tt].rt]<val[que[tt-1].rt]){
tt--;
que[tt].r=que[tt+1].r;
que[tt].rt=merge(que[tt].rt,que[tt+1].rt);
while(sz[que[tt].rt]*2>(que[tt].r-que[tt].l+2)){
pop(que[tt].rt);
}
}
}
LL ans=0;
for(i=1;i<=n;i++)
for(j=que[i].l;j<=que[i].r;j++)
ans+=abs(val[que[i].rt]-x[j]);
printf("%lld\n",ans);
return 0;
}

bzoj 1367 - sequence的更多相关文章

  1. BZOJ 1367 [Baltic2004]sequence 解题报告

    BZOJ 1367 [Baltic2004]sequence Description 给定一个序列\(t_1,t_2,\dots,t_N\),求一个递增序列\(z_1<z_2<\dots& ...

  2. 【BZOJ 1367】 1367: [Baltic2004]sequence (可并堆-左偏树)

    1367: [Baltic2004]sequence Description Input Output 一个整数R Sample Input 7 9 4 8 20 14 15 18 Sample Ou ...

  3. BZOJ 1367: [Baltic2004]sequence [可并堆 中位数]

    1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1111  Solved: 439[Submit][ ...

  4. bzoj 1367: [Baltic2004]sequence

    1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MB Description Input Output 一个整数R Sa ...

  5. bzoj 1367 [ Baltic 2004 ] sequence —— 左偏树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1367 好题啊!论文上的题: 论文上只给出了不下降序列的求法: 先考虑特殊情况,如果原序列上升 ...

  6. BZOJ 1367 [Baltic2004]sequence (可并堆)

    题面:BZOJ传送门 题目大意:给你一个序列$a$,让你构造一个递增序列$b$,使得$\sum |a_{i}-b_{i}|$最小,$a_{i},b_{i}$均为整数 神仙题.. 我们先考虑b不递减的情 ...

  7. sequence(bzoj 1367)

    Description Input Output 一个整数R Sample Input 794820141518 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15 ...

  8. BZOJ 1367([Baltic2004]sequence-左偏树+中位数贪心)

    1367: [Baltic2004]sequence Time Limit: 20 Sec   Memory Limit: 64 MB Submit: 521   Solved: 159 [ Subm ...

  9. 【BZOJ 1049】 1049: [HAOI2006]数字序列 (LIS+动态规划)

    1049: [HAOI2006]数字序列 Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变 ...

随机推荐

  1. 黑马基础阶段测试题:通过字符输入流读取info.txt中的所有内容,每次读取一行,将每一行的第一个文字截取出来并打印在控制台上。

    package com.swift; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File ...

  2. vue 组件的书写

    简单的来说是 vue组件最核心的就是props和自定义函数,来实现组件的开发 最简单的一个组件 子组件如下: <template> <div class="bgClass& ...

  3. php与js的crc32(支持中文)

    代码: <?php function myCrc32($string, $crc = 0) { $table = "00000000 77073096 EE0E612C 990951B ...

  4. Python基础:条件与循环

    条件语句 除了 boolean 类型的数据,条件判断最好是显性的 if i != 0: ... 而不是只写出变量名: if i: ... For循环与While循环 通常来说,如果你只是遍历一个已知的 ...

  5. Python9-MySQL数据库安装及基本操作-day42

    MySQL 单机程序(自己DB) 单机程序(共用DB)MySQL:用于管理文件的一个软件 -服务端软件 -socket服务端 -本地文件操作 -解析指令[SQL语句] -客户端软件(各种各样) -so ...

  6. NAND Flash和NOR Flash的比较

    目前Flash主要有两种NOR Flash和NADN Flash.NOR Flash的读取和我们常见的SDRAM的读取是一样,用户可以直接运行装载在NOR FLASH里面的代码,这样可以减少SRAM的 ...

  7. Contest - 中南大学第六届大学生程序设计竞赛(Semilive)

    题1:1160十进制-十六进制 注意他给的数据范围 2^31,int是 2^31-1 #include<iostream> using namespace std; int main() ...

  8. CodeForces 768E Game of Stones 打表找规律

    题意: 在经典Nim博弈的基础上增加了新的限制:如果从这堆石子中移走\(x\)个石子,那么之后就不能再从这堆移走\(x\)个. 分析: 因为之前的操作会对后面的转移有影响,所以在保存状态时还要记录哪些 ...

  9. 安装Mysql community server遇到计算机中丢失msvcr120.dll

    一.下载community server版本 Mysql community server版本:https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7 ...

  10. java以正确的方式停止线程

    java线程停止可以说是非常有讲究的,看起来非常简单,但是也要做好一些防范措施,一般停止一个线程可以使用Thread.stop();来实现,但是最好不要用,因为他是不安全的. 大多数停止线程使用Thr ...