題目鏈接:https://codeforces.ml/contest/1313/problem/C2
題目大意:
有n棟房子。每個房子的最高的高度b[i]應該在[1, a[i]]區間裏。現在要滿足不存在i<j<k有a[i]>a[j]<a[k]。並且要b[i]的和最大。輸出b[i]-b[n]。方案可能不唯一。隨便輸出一個就可以。
思路:我們可以知道b[i]數組是一個單峯函數。並且最高的b[i]一定等於a[i]。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL a[500005], l[500005], r[500005];
LL f[2][500005], tot=0, g[500005];
struct node{
LL x, i;
}q[500005];
int main(){
int n;scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%lld", &a[i]);
}
//單調棧
for(int i=1; i<=n; i++){
if(tot==0||q[tot].x<a[i]){
q[++tot]={a[i], i};
}
while(tot!=0&&q[tot].x>=a[i]){
l[q[tot].i]=q[tot-1].i;
r[q[tot].i]=i;
tot--;
}
q[++tot]={a[i], i};
}
while(tot){
l[q[tot].i]=q[tot-1].i;
r[q[tot].i]=n+1;
tot--;
}
//dp
for(int i=1; i<=n; i++){
if(a[i]>a[i-1]){
f[0][i]=f[0][i-1]+a[i];
}
else{
f[0][i]=f[0][l[i]]+(i-l[i])*a[i];
}
}
for(int i=n; i>=1; i--){
if(a[i]>a[i+1]){
f[1][i]=f[1][i+1]+a[i];
}
else{
f[1][i]=f[1][r[i]]+(r[i]-i)*a[i];
}
}
//方案
LL mx=0, pos=0, now=0;
for(int i=1; i<=n; i++){
if(f[0][i]+f[1][i]-a[i]>mx){
mx=f[0][i]+f[1][i]-a[i];
pos=i;
}
}
g[pos]=a[pos], now=a[pos];
for(int i=pos+1; i<=n; i++){
if(a[i]>=now){
g[i]=now;
}
else{
g[i]=a[i];
now=g[i];
}
}
now=a[pos];
for(int i=pos-1; i>=1; i--){
if(a[i]>=now){
g[i]=now;
}
else{
g[i]=a[i];
now=g[i];
}
}
for(int i=1; i<=n; i++){
printf("%lld ", g[i]);
}
return 0;
}