JZOJ-senior-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 ( n l o g n ) O(nlogn) O(nlogn) 每次选择 [ l , r ] [l,r] [l,r] 中最小的数作为覆盖的高度,然后区间被分成 [ l , r ′ ] [l,r'] [l,r] [ l ′ , r ] [l',r] [l,r],用线段树维护
100%: O ( n ) O(n) O(n) 若令 a 0 = a n + 1 = 0 a_0=a_{n+1}=0 a0=an+1=0,则 a n s = ∑ i = 1 n m a x ( 0 , a i − a i − 1 ) ans=\sum_{i=1}^{n}max(0,a_i-a_{i-1}) ans=i=1nmax(0,aiai1)

Code

#include
#include
#include

#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);
}

你可能感兴趣的:(暴力)