1. 程式人生 > 實用技巧 >Codeforces Skyscrapers (hard version)

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