CF448C Painting Fence(分治递归/DFS)难度⭐⭐⭐

题目链接
有n块连着的木板,每个木板的高度为 h i h_i ,你需要把这n块木板上色,每次 上色你可以选择竖着刷完一块木板,或者横着刷一个高度单位的连续的木板(不能中 间空着的不能跳跃),问最少需要刷几次。(注意相当于有一个宽1的刷子,每次可以刷无限长但是宽度只有1)

5
2 2 1 2 1
3
2
2 2
2

考虑横着涂一次的情况,那么有两个显而易见的事实。
这次涂色长度必须尽可能大。
在这次涂色区域的下方,必定都是横着涂的。
所以,对于一串栅栏 h 1 , h 2 , , h n h_1,h_2,…,h_n ,如果要横着涂,就必定要从底向上涂 m i n ( h 1 , h 2 , , h n ) min⁡{(h_1,h_2,…,h_n)} 次。这样以后, h 1 , h 2 , , h n h_1,h_2,…,h_n 就会分成若干不连通的子局面。

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

有任何疑问欢迎评论哦虽然我真的很菜

发布了110 篇原创文章 · 获赞 92 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_45697774/article/details/104712705