CF448C Painting Fence

Posted ppxppx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF448C Painting Fence相关的知识,希望对你有一定的参考价值。

题意:有n块连着的木板,每个木板的高度为(h_i),你需要把这n块木板上色,每次上色你可以选择竖着刷完一块木板,或者横着刷一个高度单位的连续的木板(不能跳跃),问最少需要刷几次?

分析:先只考虑贪心地横着涂:每一次尽可能地涂最长,且在此次横着涂的下方必定都是横着涂的,因为如果下面有竖着涂的,根据最优性,上一次竖着涂的时候肯定要把此次的也涂掉(这个自己想想很容易明白,对于一根木板,绝对不可能下面竖着涂,上面横着涂)

所以对于一串连着的木板(h_1),(h_2)...(h_n),就必定是从下往上涂min{(h_1),(h_2)...(h_n)}次,这样以后(h_1),(h_2)...(h_n)就被分成了几串不连通的木板(子局面),说到这里,可以发现本题可以用分治解决,时间复杂度(O(N^2)).

设work(l,r,now)表示对于[l,r]这一串连着的木板,已经从下往上涂了now格时的答案.

设minh=min{(h_1),(h_2)...(h_n)},则work(l,r,now)=min(r-l+1,(sum work(u,v,minh))),其中[u,v]是分割出的一个子局面.至于为什么还要与r-l+1取min?因为如果横着涂比直接竖着涂要麻烦,那就不如直接每一根木板都竖着涂呗,一共有r-l+1根木板.

最后注意一下边界情况l=r时,显然只有一根木板的话,那就直接竖着涂一次完事了.

int n,h[5005];
int work(int l,int r,int now){
    if(l==r)return 1;//边界情况
    int i,j,ans=0,minh=1e9;
    for(i=l;i<=r;i++)
        if(h[i]<minh)minh=h[i];
//找到[l,r]这一串木板中最短的木板
    ans+=minh-now;//记得减去之前已经涂了的now格
    for(i=l;i<=r;i++){//分割成子局面并处理
        if(h[i]==minh)continue;
        for(j=i;j<=r;j++)
            if(h[j+1]==minh||j==r)break;
        ans+=work(i,j,minh);
        i=j+1;//刚开始忘记了这里
    }
    return min(r-l+1,ans);//与竖着涂取min
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)h[i]=read();
    printf("%d
",work(1,n,0));
    return 0;
}

以上是关于CF448C Painting Fence的主要内容,如果未能解决你的问题,请参考以下文章

[Codeforces 448C]Painting Fence

CodeForces 448C Painting Fence

Codeforces 448C Painting Fence(分治法)

Codeforces 448C Painting Fence:分治

cf 448 C. Painting Fence

C. Painting the Fence