U138026 土地恢复

原题链接

U138026 土地恢复

题目大意

有一个长度为 n ( 1 ≤ n ≤ 100000 ) n(1\le n\le 100000) n(1n100000)的土地,每个位置都有一个深度 d e p t h ( 0 ≤ d e p t h ≤ 10000 ) depth(0\le depth \le 10000) depth(0depth10000),每次可以选择 [ n , m ] [n,m] [n,m]的区间,让其中的每一处深度减一,求最少需要多少次,才能让所有位置的深度都为0。

解题思路

我们可以先以这组数据为例子:

输入

6
4 3 2 5 3 5

输出

9

以这个样例为例,我们可以画出一张图:

0
1
2
3 1
4 1 1 1
5 1 1 1 1

由于要在较少的次数内填完,我们可以使用一个贪心的思路,填的区间尽量的大,也就是说,在这种情况下,我们可以先填 [ 1 , 6 ] [1,6] [1,6],直到有零出现(2次):

0
1 1
2 1 1 1
3 1 1 1 1
4 1 1 1 1 1 1
5 1 1 1 1 1 1

这时候,区间就要缩小了,出现0之后,整个土地被分成了两段,分别为 [ 1 , 2 ] [1,2] [1,2]和, [ 4 , 6 ] [4,6] [4,6]。我们可以分开来处理,再重复上面的步骤(先处理左边):

0
1 1 1
2 1 1 1 1
3 1 1 1 1
4 1 1 1 1 1 1
5 1 1 1 1 1 1

共3次

0
1 1 1 1
2 1 1 1 1
3 1 1 1 1
4 1 1 1 1 1 1
5 1 1 1 1 1 1

共4次

0
1 1 1 1 1
2 1 1 1 1
3 1 1 1 1 1 1
4 1 1 1 1 1 1
5 1 1 1 1 1 1

共5次

0
1 1 1 1 1 1
2 1 1 1 1 1
3 1 1 1 1 1 1
4 1 1 1 1 1 1
5 1 1 1 1 1 1

共7次

0
1 1 1 1 1 1 1
2 1 1 1 1 1 1
3 1 1 1 1 1 1
4 1 1 1 1 1 1
5 1 1 1 1 1 1

共9次
如果按照上面的做法,有点像 d f s dfs dfs,为了骗分,我敲了一下(如果不是数据太水,我就过不了了,此算法时间复杂度为 O ( n 2 ) O(n^2) O(n2)!):

void dfs(int l,int r)//l和r分别为区间左端和区间右端
{
    
    
	if(r-l==0){
    
    //区间长度为1
		ans+=a[l];//填平
		return;
	}
	if(l>r)
		return;//超界
	int Min=100010;//记录区间内最小值
	for(int i=l;i<=r;i++)
		Min=min(Min,a[i]);
	for(int i=l;i<=r;i++)
		a[i]-=Min;//填区间
	ans+=Min;//记录答案,因为每次只能填一格,所以一共要填Min次
	int x=l-1;
	for(int i=l;i<=r;i++){
    
    
		if(a[i]==0){
    
    //零点划分
			dfs(x+1,i-1);
			x=i;
		}
	}
	if(a[r]!=0)
		dfs(x+1,r);//特判
}

代码实现

#include<bits/stdc++.h>
using namespace std;
int a[100010],ans,n;
void dfs(int l,int r)//l和r分别为区间左端和区间右端
{
    
    
	if(r-l==0){
    
    //区间长度为1
		ans+=a[l];//填平
		return;
	}
	if(l>r)
		return;//超界
	int Min=100010;//记录区间内最小值
	for(int i=l;i<=r;i++)
		Min=min(Min,a[i]);
	for(int i=l;i<=r;i++)
		a[i]-=Min;//填区间
	ans+=Min;//记录答案,因为每次只能填一格,所以一共要填Min次
	int x=l-1;
	for(int i=l;i<=r;i++){
    
    
		if(a[i]==0){
    
    //零点划分
			dfs(x+1,i-1);
			x=i;
		}
	}
	if(a[r]!=0)
		dfs(x+1,r);//特判
}
int main()
{
    
    
	ios::sync_with_stdio(false);
	cin.tie();
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	dfs(1,n);//初始区间左右端点
	cout<<ans;
}

样例1

输入

6
4 3 2 5 3 5

输出

9

样例2

输入

4
2 5 3 5

输出

7

样例3

输入

12
2 6 5 8 9 12 15 7 5 10 16 24

输出

35

おすすめ

転載: blog.csdn.net/weixin_41247488/article/details/120674781