Codeforces Round #622 Div2C Skyscrapers

首都的郊区正在柏林积极建设。该公司“核心恐慌”管理着新伯尔斯科瓦一座摩天大楼住宅区的建设。所有的摩天大楼都是沿着公路建的。据了解,该公司已经在高速公路沿线购买了n块地,并准备建造n座摩天大楼,每块地一座摩天大楼。

建筑师在规划摩天大楼时必须考虑几个要求。首先,由于每个地块上的土地都有不同的属性,因此每个摩天大楼的最大楼层数都有限制。其次,根据城市设计规范,一座摩天大楼的左右两侧同时拥有更高的摩天大楼是不可接受的。

从形式上讲,让我们把图从1数到n,然后如果第i个图上的摩天大楼有ai层,它必须保持ai最多为mi(1≤ai≤mi)。也不能有整数j和k,这样j<i<k和aj>ai<ak。图j和k不要求与i相邻。

该公司希望已建成的摩天大楼的总层数尽可能大。帮助其以最佳方式为每个摩天大楼选择层数,即以满足所有要求的方式,并在所有此类施工计划中选择具有最大可能总层数的任何计划。

输入

第一行包含一个整数n(1≤n≤1000)-绘图数。

第二行包含整数m1,m2,…,mn(1≤mi≤109)-每个地块上摩天大楼每可能楼层数的楼层数限制。

输出

打印n个整数ai-每个摩天大楼的平面图中的楼层数,以便满足所有要求,并且所有摩天大楼的总楼层数是最大可能的。

如果可能有多个答案,请打印其中任何一个。

题解:

单调栈算法。

开一个栈,栈里只存放单调递增序列,l数组保存以这栋楼为最高峰的情况下包括它自己在内左边所有楼的总楼层,r数组保存以这栋楼为最高峰的情况下包括它自己在内右边所有楼的总楼层。

总体是一个分治的思想。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+14;
ll a[maxn];
ll l[maxn];
ll r[maxn];
int main () {
    int N;
    while (~scanf("%d",&N)) {
        stack<int> st;
        for (int i=1;i<=N;i++) scanf("%d",&a[i]);
        for (int i=1;i<=N;i++) {
            while (!st.empty()&&a[st.top()]>=a[i])
                st.pop();
            if (st.empty()) l[i]=i*a[i];
            else l[i]=l[st.top()]+(i-st.top())*a[i];
            st.push(i);
        }
        while (!st.empty()) st.pop();
        for (int i=N;i>=1;i--) {
            while (!st.empty()&&a[st.top()]>=a[i])
                st.pop();
            if (st.empty()) r[i]=(N-i+1)*a[i];
            else r[i]=r[st.top()]+(st.top()-i)*a[i];
            st.push(i);
        }
        ll ans=0;
        ll id=0;
        for (int i=1;i<=N;i++) {
            ll tmp=l[i]+r[i]-a[i];
            if (tmp>ans) {
                ans=tmp;
                id=i;
            }
        }
        for (int i=id-1;i>=1;i--) a[i]=min(a[i],a[i+1]);
        for (int i=id+1;i<=N;i++) a[i]=min(a[i],a[i-1]);
        for (int i=1;i<=N;i++) printf ("%d ",a[i]);
        printf ("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zhanglichen/p/12391495.html