Skyscrapers (hard version)
题目链接:https://codeforces.com/contest/1313/problem/C2
解题思路:我们最后建好的高楼一定是一个倒v的形状,因此我们可以考虑用一个数组s[i]表示最高点位于位置i的时候能够得到的最大值,则在i点的两个一定是单调递减的(也可以看作单调递增的,从两边往中间看的话)则我们用一个单调栈来维护这个序列 从两边往中间楼高一定是递增的,因此维护一个单调递减栈,当我们新加入一个楼时,如果比栈顶元素的高度要高,则高度和就可以加上新楼的高度,但是如果比当前的小的话,就要进行出栈处理并且减掉这些出栈的楼的影响,最后再加上新楼的高度*删去的楼的数目就行(相当于把之前不符合的全部减小了一下),最后统计答案即可
#include<bits/stdc++.h> using namespace std; const int maxn=5e5+10; typedef unsigned long long ll; stack<int>q; ll a[maxn],s[maxn],n; void getans(int flag) { /* 1和0分别表示从左向右和从右向左,因此会有不同的处理方式,同时再从右向左的时候,最高点会被枚举两次,因此需减少一下*/ ll sum=0; q.push(0); for(int i=1;i<=n;i++) { while(!q.empty()&&a[i]<a[q.top()]) { int now=q.top(); q.pop(); sum-=1ll*(now-q.top())*a[now]; } sum+=1ll*(i-q.top())*a[i]; if(flag) s[i]+=sum; else s[n-i+1]+=sum-a[i]; q.push(i); } while(!q.empty()) q.pop(); } int main() { /*Codeforces 1313*/ cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; getans(1); reverse(a+1,a+1+n); getans(0); reverse(a+1,a+1+n); int pos=max_element(s+1,s+1+n)-s; // for(int i=1;i<=n;i++) cout<<s[i]<<" "; for(int i=pos-1;i;i--) if(a[i]>a[i+1]) a[i]=a[i+1]; for(int i=pos+1;i<=n;i++) if(a[i]>a[i-1]) a[i]=a[i-1]; for(int i=1;i<=n;i++) cout<<a[i]<<" "; cout<<endl; return 0; } //-8 4 -2 -6 4 7 1 //1 0 0 0 1 1 0