質問の意味:
長さの配列を考えるとnは、
今の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[]同理,而找某个位置左边或者右边第一个比它小的位置是单调栈的基础操作,因此用单调栈就能实现
コード:
#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;
}