CF102920L Two Buildings【分治】【决策单调性】
优秀的分治题目。是“2020-2021 ACM-ICPC, Asia Seoul Regional Contest”的一道题。
Description
There are \(n\) buildings along a horizontal street. The buildings are next to each other along the street, and the \(i\)-th building from left to right has width \(1\) and height \(h_i\). Among the \(n\) buildings, we are to find two buildings, say the \(i\)-th building and \(j\)-th building with \(i<j\), such that \((h_i+h_j)*(j−i)\) is maximized.
For example, the right figure shows \(5\) buildings, with heights \(1\), \(3\), \(2\), \(5\), \(4\), from left to right. If we choose the first \(2\) buildings, then we get \((1+3)*(2−1)=4\). If we choose the first and fifth buildings, then we \((1+4)*(5−1)=20\). The maximum value is achieved by the second and fifth buildings with heights \(3\) and \(4\), respectively: \((3+4)*(5−2)=21\).
Write a program that, given a sequence of building heights, prints \(\max_{1\le i<j\le n}(h_i+h_j)*(j−i)\).
Input
Your program is to read from standard input. The input starts with a line containing an integer \(n\) (\(2\le n\le 1,000,000\)), where \(n\) is the number of buildings. The buildings are numbered \(1\) to \(n\) from left to right. The second line contains the heights of \(n\) buildings separated by a space such that the \(i\)-th number is the height \(h_i\) of the \(i\)-th building (\(1\le h_i\le 1,000,000\)).
Output
Your program is to write to standard output. Print exactly one line. The line should contain \(\max_{1\le i<j\le n}(h_i+h_j)*(j−i)\).
Examples
input
5
1 3 2 5 4
output
21
input
5
8 3 6 3 1
output
36
题意:
有 \(n(2\le n\le 1000000)\) 栋楼房,第 \(i\) 栋高度为 \(h_i(1\le h_1\le 1000000)\)。问两栋楼房所能构成的 \((h_i+h_j)*(j−i)\) 最大值是多少。
题解:
为了方便,我们把要求的式子转化为 \((h_i-(-h_j))\times(j-i)\),这样构造出数列 \(-h_i\),就是坐标系中 \(x\) 轴上方和 \(x\) 轴下方两个数列中选出两个 \(h\) 进行计算。
如果存在 \(i<j\),同时 \(-h_i<-h_j\),那么 \(j\) 一定比 \(i\) 更优。可以用单调栈来把数列 \(\{h_i\}\) 和 \(\{-h_i\}\) 都变为单调的。得到单增的 \(\{H_i\}\) 和 \(\{-H_i\}\)。

如图,图中橙色的点删除后,对答案产生贡献的点只会在蓝色中产生。
而蓝色的点 \(\{H_i\}\) 和 \(\{-H_i\}\) 对应了两段递增的序列(此时下标 \(i\) 不一定连续)。最终答案为 \([H_i-(-H_j)]\times(j-i)\)。假设对于选定的 \(H_i\),对应 \(-H_j\) 为最优解,即 \(\forall k>j,[H_i-(-H_j)]\times(j-i)\geqslant[H_i-(-H_k)]\times(k-i)\),可知
[H_i-(-H_j)]\times(j-i)&\geqslant[H_i-(-H_k)]\times(k-i)\\\
[H_i-(-H_j)]\times(j-i)\color{red}{-[H_i-(-H_k)]\times(j-i)}&\geqslant[H_i-(-H_k)]\times(k-i)\color{red}{-[H_i-(-H_k)]\times(j-i)}\\\
[(-H_k)-(-H_j)]\times(j-i)&\geqslant[H_i-(-H_k)]\times(k-j)
\end{aligned}\]
因此对于 \(l<i\),对上式进行放缩,得
[(-H_k)-(-H_j)]\times(j-i)&\geqslant[H_i-(-H_k)]\times(k-j)\\\
[(-H_k)-(-H_j)]\times(j-i)\color{blue}{+[(-H_k)-(-H_j)]\times(i-l)}&\geqslant[H_i-(-H_k)]\times(k-j)\color{red}{-(H_i-H_l)\times(k-j)}\\\
[(-H_k)-(-H_j)]\times(j-l)&\geqslant[H_l-(-H_k)]\times(k-j)\\\
[(-H_k)-(-H_j)]\times(j-l)\color{blue}{+[H_l-(-H_k)]\times(j-l)}&\geqslant[H_l-(-H_k)]\times(k-j)\color{blue}{+[H_l-(-H_k)]\times(j-l)}\\\
[H_l-(-H_j)]\times(j-l)&\geqslant[H_l-(-H_k)]\times(k-l)
\end{aligned}\]
所以当 \(H_i\) 对应的最优解位置为 \(-H_j\) 时,\(l<i\) 的 \(H_l\) 对应的最优解位置 \(-H_k\) 满足 \(k\geqslant j\)。
如果上式推导过于复杂,它对应的图形推导如下。

左图中,如果 \(H_i\) 对应的最优解是 \(H_j\),那么①的面积 \(S_1\) 一定比②的 \(S_2\) 大。右图中,那么对 \(l<i\),已知 \(S_1\geqslant S_2\),有 \(S_1+S_3\geqslant S_2-S_4\),所以 \(l\) 对应的最优解一定不会在 \(j\) 右边。
此时再考虑上边的推导,便能清楚理解了。
分治递归,时间复杂度为 \(O(n\log n)\)。
Code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
int a[1001000],b[1001000],c[1001000];
int bp[1001000],cp[1001000];
ll ans=0;
void solve(int l,int r,int L,int R)
{
if(l>r)
return;
int mid=(l+r)>>1,q=0;
ll Ans=0;
for(int i=L;i<=R;++i)
{
if(Ans<1ll*(cp[i]-bp[mid])*(b[mid]+c[i]))
{
q=i;
Ans=1ll*(cp[i]-bp[mid])*(b[mid]+c[i]);
}
}
ans=ans>Ans?ans:Ans;
solve(l,mid-1,L,q);
solve(mid+1,r,q,R);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
int ii=0,iii=0;
c[0]=1e8;
for(int i=1;i<=n;++i)
{
if(a[i]>b[ii])
{
b[++ii]=a[i];
bp[ii]=i;
}
while(a[i]>=c[iii])
--iii;
c[++iii]=a[i];
cp[iii]=i;
}
solve(1,ii,1,iii);
printf("%lld\n",ans);
return 0;
}
CF102920L Two Buildings【分治】【决策单调性】的更多相关文章
- CF868F Yet Another Minimization Problem 分治决策单调性优化DP
题意: 给定一个序列,你要将其分为k段,总的代价为每段的权值之和,求最小代价. 定义一段序列的权值为$\sum_{i = 1}^{n}{\binom{cnt_{i}}{2}}$,其中$cnt_{i}$ ...
- bzoj2216: [Poi2011]Lightning Conductor(分治决策单调性优化)
每个pi要求 这个只需要正反DP(?)一次就行了,可以发现这个是有决策单调性的,用分治优化 #include<iostream> #include<cstring> #incl ...
- [BZOJ2739]最远点(DP+分治+决策单调性)
根据旋转卡壳,当逆时针遍历点时,相应的最远点也逆时针转动,满足决策单调性.于是倍长成链,分治优化DP即可,复杂度O(n^2). #include<cstdio> #include<a ...
- BZOJ2739 最远点(分治 + 决策单调性)
2739: 最远点 Time Limit: 20 Sec Memory Limit: 256 MB Description 给你一个N个点的凸多边形,求离每一个点最远的点. Input 本题有多组数据 ...
- 决策单调性&wqs二分
其实是一个还算 trivial 的知识点吧--早在 2019 年我就接触过了,然鹅当时由于没认真学并没有把自己学懂,故今复学之( 1. 决策单调性 引入:在求解 DP 问题的过程中我们常常遇到这样的问 ...
- CodeForces 868F Yet Another Minimization Problem(决策单调性优化 + 分治)
题意 给定一个序列 \(\{a_1, a_2, \cdots, a_n\}\),要把它分成恰好 \(k\) 个连续子序列. 每个连续子序列的费用是其中相同元素的对数,求所有划分中的费用之和的最小值. ...
- P2877 [USACO07JAN]牛校Cow School(01分数规划+决策单调性分治)
P2877 [USACO07JAN]牛校Cow School 01分数规划是啥(转) 决策单调性分治,可以解决(不限于)一些你知道要用斜率优化却不会写的问题 怎么证明?可以暴力打表 我们用$ask(l ...
- 洛谷CF868F Yet Another Minimization Problem(动态规划,决策单调性,分治)
洛谷题目传送门 貌似做所有的DP题都要先搞出暴力式子,再往正解上靠... 设\(f_{i,j}\)为前\(i\)个数分\(j\)段的最小花费,\(w_{l,r}\)为\([l,r]\)全在一段的费用. ...
- bzoj 2739 最远点——分治处理决策单调性
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2739 分治处理决策单调性的思想就是先找到一个询问,枚举所有可能的转移找到它的决策点,那么这个 ...
- 4951: [Wf2017]Money for Nothing 决策单调性 分治
Bzoj4951:决策单调性 分治 国际惯例题面:一句话题面:供应商出货日期为Ei,售价为Pi:用户收购截止日期为Si,收购价格为Gi.我们要求max((Si-Ej)*(Gi-Pj)).显然如果我们把 ...
随机推荐
- react空标签之The React Fragment
如何使用React.Fragment创建不可见的HTML标签 在研究Ant Design Pro项目中,在登录模块中,有React.Fragment的实际应用 接下来先看一个小demo,将返回值包装在 ...
- Geospark-属性字段处理
Geospark将从shapefile.csv等格式文件以及DataFrame中的读取的字段保存到了Geometry的userData字段中,可以通过调用.getUserData()方法获取,他会返回 ...
- Python3爬取猫眼电影信息
Python3爬取猫眼电影信息 import json import requests from requests.exceptions import RequestException import ...
- ubuntu 安装新版的qq,可支持下载文件等常用功能
说明:此版本的QQ基本完美,但是有个缺点就是历史记录有些会显示乱码! 注意:此方法能完美解决这篇文章http://www.cnblogs.com/EasonJim/p/7118693.html的所有问 ...
- 关闭Linux - centos7的防火墙
关闭Centos7的防火墙 在每台虚拟机上分别执行以下指令: systemctl stop firewalld.service #停止firewall systemctl disable firewa ...
- Python: 捕获正在运行的CMD窗口内容
最近需要捕获已经在运行的CMD窗口内容,并且需要根据指定输出内容来判断下一步的行动(输入指定内容). 尝试了很多次后,想到一个思路: 通过inspect.exe来获取CMD窗口Name信息通过uiau ...
- EF6.2加载速度慢的解决方案
最近的项目中一直有反馈,EF在第一次启动之后调用的话,加载速度很慢,在网上搜索了一下,基本就是三种解决方案. 在程序启动的时候将映射视图缓存下来. 使用Ngen生成EF的本地镜像. IIS8内置功能 ...
- trie浅谈
关于trie 其实字典树和以上两种算法有很大不同,但是hash由于其优秀的应用,导致有些字符串查找用hash也是可行的. 字典树中支持添加,查找,区间查询(可持久化字典树),而且在异或操作上有 ...
- 洛谷P5496 回文自动机【PAM】模板
回文自动机模板 1.一个串的本质不同的回文串数量是\(O(n)\)级别的 2.回文自动机的状态数不超过串长,且状态数等于本质不同的回文串数量,除了奇偶两个根节点 3.如何统计所有回文串的数量,类似后缀 ...
- 【bzoj 3433】{Usaco2014 Jan} Recording the Moolympics(算法效率--贪心)
题意:给出n个区间[a,b),有2个记录器,每个记录器中存放的区间不能重叠.求2个记录器中最多可放多少个区间. 解法:贪心.只有1个记录器的做法详见--关于贪心算法的经典问题(算法效率 or 动态规划 ...