原题链接
题目大意
有一个长度为 n ( 1 ≤ n ≤ 100000 ) n(1\le n\le 100000) n(1≤n≤100000)的土地,每个位置都有一个深度 d e p t h ( 0 ≤ d e p t h ≤ 10000 ) depth(0\le depth \le 10000) depth(0≤depth≤10000),每次可以选择 [ 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