題意:
給定長度爲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;
}