Codeforces Skyscrapers (hard version)

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

 

posted @ 2020-09-17 20:02  mcalex  阅读(128)  评论(0编辑  收藏  举报