题意:
给定长度为n的数组a,
现在要在这n个位置建立大厦,但是要满足一下要求:
1.位置pos的高度h[pos]不能超过a[pos]
2.位置pos左边和右边不能有高于h[pos]
输出高度和最大的建立方案(输出每个位置的高度h)
n<=5e5
思路:
easy版本n只有1000,可以直接枚举最高大厦的位置,然后暴力计算答案,复杂度O(n^2)
hard版本数据范围很大,枚举显然不行
思考如何利用i-1的答案推导出出i的答案
设l[i]为位置i为峰时,i及其左半部分最大高度和
设r[i]为位置i为峰时,i及其右半部分最大高度和
则以i为峰的高度和就是l[i]+r[i]-a[i]
计算l[]和r[]:
假设i是j左边第一个高度限制小于j的,那么l[j]=l[i]+(j-i)*a[j]
因为i到j中间部分k的高度限制大于j,那么最高建到a[j],
i以及左边部分是已经计算出来的d[i],两者相加就是j位置的答案
计算r[]同理,而找某个位置左边或者右边第一个比它小的位置是单调栈的基础操作,因此用单调栈就能实现
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=5e5+5;
int a[maxm];
int l[maxm],r[maxm];
int stk[maxm],head;
int ans[maxm];
signed main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
head=0;
stk[0]=0;
for(int i=1;i<=n;i++){
while(head&&a[stk[head]]>a[i]){
head--;
}
l[i]=l[stk[head]]+(i-stk[head])*a[i];
stk[++head]=i;
}
head=0;
stk[0]=n+1;
for(int i=n;i>=1;i--){
while(head&&a[stk[head]]>a[i]){
head--;
}
r[i]=r[stk[head]]+(stk[head]-i)*a[i];
stk[++head]=i;
}
int pos=0;
int ma=0;
for(int i=1;i<=n;i++){
if(l[i]+r[i]-a[i]>ma){
ma=l[i]+r[i]-a[i];
pos=i;
}
}
ans[pos]=a[pos];
for(int i=pos-1;i>=1;i--){
ans[i]=min(ans[i+1],a[i]);
}
for(int i=pos+1;i<=n;i++){
ans[i]=min(ans[i-1],a[i]);
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<' ';
}
cout<<endl;
return 0;
}
来源:CSDN
作者:我到底在干嘛
链接:https://blog.csdn.net/weixin_44178736/article/details/104544257