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
31
4111
51111

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

0
11
2111
31111
4111111
5111111

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

0
111
21111
31111
4111111
5111111

共3次

0
1111
21111
31111
4111111
5111111

共4次

0
11111
21111
3111111
4111111
5111111

共5次

0
111111
211111
3111111
4111111
5111111

共7次

0
1111111
2111111
3111111
4111111
5111111

共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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值