题目链接
有n块连着的木板,每个木板的高度为 hi,你需要把这n块木板上色,每次 上色你可以选择竖着刷完一块木板,或者横着刷一个高度单位的连续的木板(不能中 间空着的不能跳跃),问最少需要刷几次。(注意相当于有一个宽1的刷子,每次可以刷无限长但是宽度只有1)
5
2 2 1 2 1
3
2
2 2
2
考虑横着涂一次的情况,那么有两个显而易见的事实。
这次涂色长度必须尽可能大。
在这次涂***域的下方,必定都是横着涂的。
所以,对于一串栅栏 h1,h2,…,hn,如果要横着涂,就必定要从底向上涂 min(h1,h2,…,hn)次。这样以后, h1,h2,…,hn就会分成若干不连通的子局面。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ifstream in("input.txt");
ofstream out("output.txt");
#define debug(x) cerr<<"# "<<x<<endl
const ll N=2e5;
const ll base=137;
const ll mod=2147483647;
const ll INF=1<<30;
ll n,m;
ll a[N],b[N];
ll DFS(ll l,ll r,ll h)
{
if(l==r)return 1;
if(l>r)return 0;
ll ans=0,minn=INF,la=l-1;
for(int i=l;i<=r;++i)
minn=min(minn,a[i]);
ans=minn-h;
for(int i=l;i<=r;++i)
if(a[i]==minn)
ans+=DFS(la+1,i-1,minn),la=i;//表明左边已经找过了,例行地找的话从la=i开始避免重复查找
ans+=DFS(la+1,r,minn);//例行公事
return min(ans,r-l+1);//比较横着涂和竖着涂那个最小
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
printf("%lld\n",DFS(1,n,0));
return 0;
}
有任何疑问欢迎评论哦虽然我真的很菜