题目链接
题目大意:
求一段序列的 (h[i]+h[j])*(j-i) 的最大值
step1: 转化一下题意
(h[i]+h[j])(j-i) = ( h[j] - (-h[i]) )(j-i)
令a[i] = -h[i] ,b[i] = h[i]
然后全部转化为两种坐标 (i,a[i]) (i,b[i])
这样题目就转化成了在一个坐标系中 求最大矩形的面积(选出左下角和右上角的点)
step2: 去除一些多余的点
对于一个固定的(i,a[i])坐标,要想矩形面积最大,肯定是越往左上越好
对于 b[j] < b[i] (j<i) 这样的(j,b[j])可以全部除去
除去后(i,b[i] ) 呈现单调递减
同理对(i,a[i] ) 数组操作
step3:分治:
令solve(l1,r1,l2,r2) 为 a数组在mid处取左下角,b数组在[l2,r2]中取右上角,其最优值的点为pos
这里有一个结论:
mid的对应最优点取值在pos,那么[mid+1,r1]的对应最优取值一定在[pos,r2]
证明:
只需要证明在mid+x取值时然后在[l2,pos]任意位置取值构成的矩形都小于 S(mid,pos)的取值证明还是蛮简单的
之后我们要对三者
solve(l1,r1,l2,r2)
solve(l1,mid-1,l2,pos2)
solve(mid+1,r1,pos2,r2)
取最大值就🆗
CODE:
ll n, h[maxn], cnta, cntb, a[maxn], b[maxn];
ll cal(ll i, ll j) {
return (h[b[j]] + h[a[i]]) * (b[j] - a[i]);
}
ll slove(ll l1, ll r1, ll l2, ll r2) {
if (l1 > r1 || l2 > r2)
return 0;
ll ma = 0;
ll mid = (l1 + r1) >> 1, pos = l2;
ma = cal(mid, l2);
for (int i = l2 + 1; i <= r2; i++) {
if (a[mid] < b[i]) {
ll temp = cal(mid, i);
if (temp > ma) {
ma = temp;
pos = i;
}
}
}
ll t = max(slove(l1, mid-1, l2, pos), slove(mid+1 , r1, pos, r2));
ma = max(ma, t);
return ma;
}
int main() {
// ios::sync_with_stdio(false);
n = read();
rep(i, 1, n) h[i] = read();
for (int i = n; i >= 1; i--) {
if (!cntb)
b[++cntb] = i;
else if (h[i] > h[b[cntb]])
b[++cntb] = i;
}
for (int i = 1; i <= n; i++) {
if (!cnta)
a[++cnta] = i;
else if (h[i] > h[a[cnta]])
a[++cnta] = i;
}
reverse(b + 1, b + 1 + cntb);
out(slove(1, cnta, 1, cntb));
return 0;
}