1. 程式人生 > >5961. 【NOIP2018提高組D1T1】鋪設道路

5961. 【NOIP2018提高組D1T1】鋪設道路

Time Limits: 1000 ms Memory Limits: 524288 KB

Description

春春是一名道路工程師,負責鋪設一條長度為 n 的道路。
鋪設道路的主要工作是填平下陷的地表。整段道路可以看作是 n 塊首尾相連的區域,一開始,第 i 塊區域下陷的深度為 d[i] 。
春春每天可以選擇一段連續區間 [L,R] ,填充這段區間中的每塊區域,讓其下陷深度減少1。在選擇區間時,需要保證,區間內的每塊區域在填充前下陷深度均不為 0 。
春春希望你能幫他設計一種方案,可以在最短的時間內將整段道路的下陷深度都變為 0 。

Input

輸入檔名為road.in
輸入檔案包含兩行,第一行包含一個整數 n ,表示道路的長度。
第二行包含 n 個整數,相鄰兩數間用一個空格隔開,第 i 個整數為 d[i] 。

Output

輸出檔名為road.out。
輸出檔案僅包含一個整數,即最少需要多少天才能完成任務。

Sample Input

【輸入輸出樣例1】
6
4 3 2 5 3 5
【輸入輸出樣例2】
見選手目錄下的road/road2.in和road/road2.ans。

Sample Output

9

Data Constraint

【樣例解釋】
一種可行的最佳方案是,依次選擇:
[1,6],[1,6],[1,2],[1,1],[4,6],[4,4],[4,4],[6,6],[6,6]

Hint

對於 30% 的資料,1≤n≤10;
對於 70% 的資料,1≤n≤1000;
對於 100% 的資料,1≤n≤100000,0≤di≤10000。

Solution

100%:O(nlogn)O(nlogn) 每次選擇 [l,r][l,r] 中最小的數作為覆蓋的高度,然後區間被分成 [l,r][l,r'][l,r][l',r],用線段樹維護
100%:O(n)O(n) 若令a0=an+1=0a_0=a_{n+1}=0,則ans=i=1nmax(0,aiai1)ans=\sum_{i=1}^{n}max(0,a_i-a_{i-1})

Code

#include<algorithm>
#include<cstdio> #include<cctype> #define fo(i,a,b) for(int i=a;i<=b;++i) #define fd(i,a,b) for(int i=a;i>=b;--i) using namespace std; const int N=1e5+5; int n,a[N],z[N]; inline void read(int &n) { int x=0,w=0; char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); n=w?-x:x; } inline void write(int x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } int main() { freopen("road.in","r",stdin); freopen("road.out","w",stdout); read(n); int cnt=0,ans=0; fo(i,1,n) read(a[i]); fo(i,1,n) { int now=cnt; while(cnt&&a[i]<=z[cnt]) --cnt; if(now==cnt) ans+=(a[i]-z[cnt]); z[++cnt]=a[i]; } write(ans); }