Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version)

题目链接:http://codeforces.com/contest/1313/problem/C2

题意:有n个房子,每个房子可以建的最高层数为a[i],但不可以出现相邻左右两边房子的层数都比中间高的情况,要求总共层数要尽可能的多,输出每个房子应该建几层。

思路:记录左边比自己小的第一个元素,同时可以求出当i为顶端是的前缀和。然后记录右边第一个比自己小的元素,同时可以求出当i为顶端是的后缀和。然后再遍历一篇,看谁为顶端时,总层数最多,最后再依次确定层数即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
typedef long long ll;
using namespace std;
priority_queue<pair<ll, ll> >que;
ll a[500005],b[500005],c[500005],sum[500005],sum1[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(a[i-1]<=a[i])
        {
            b[i]=i-1;
            sum[i]=sum[i-1]+a[i];
        }
        else
        {
            int x=i-1;
            while(1)
            {
                x=b[x];
                if(a[x]<=a[i])
                {
                    sum[i]=sum[x]+(i-x)*a[i];
                    b[i]=x;
                    break;
                }
            }
        }
    }
    for(int i=n;i>=1;i--)
    {
        if(a[i]>=a[i+1])
        {
            c[i]=i+1;
            sum1[i]=sum1[i+1]+a[i];
        }
        else
        {
            int x=i+1;
            while(1)
            {
                x=c[x];
                if(a[x]<=a[i])
                {
                    sum1[i]=sum1[x]+(x-i)*a[i];
                    c[i]=x;
                    break;
                }
            }
        }
    }
    ll ma=0,p;
    for(int i=1;i<=n;i++)
    {
        if(sum[i]+sum1[i]-a[i]>ma)
        {
            ma=sum[i]+sum1[i]-a[i];
            p=i;
        }
    }
    ll mi=a[p];
    for(int i=p-1;i>=1;i--)
    {
        mi=min(mi,a[i]);
        a[i]=mi;
    }
    mi=a[p];
    for(int i=p+1;i<=n;i++)
    {
        mi=min(mi,a[i]);
        a[i]=mi;
    }
    for(int i=1;i<n;i++)
        printf("%lld ",a[i]);
    printf("%lld
",a[n]);
}
原文地址:https://www.cnblogs.com/zcb123456789/p/12357500.html