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\n",work(1,n,0));
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/10359976.html

时间: 2024-10-16 11:42:38

CF448C Painting Fence的相关文章

CF448C Painting Fence (贪心分治)

题面 \(solution:\) 一道蛮水的分治题,但思想很不错(虽然我还是非常天真的以为是积木大赛原题,并且居然还有30分) 看到这个题目,根据贪心的一贯风格,我们肯定能想到将整个栅栏的下面某部分直接用几次横向的操作把它涂掉.然后我们发现如果将涂了色的部分不管,整段栅栏会被我们分成若干个部分(最短的竖条栅栏因为贪心会被横着涂完,然后整个栅栏会被分为左(中)右几个部分).然后我们将这几个依次用这种办法分治.再然后我们发现我们好像把纵向操作忘记了,它在什么地方用呢?我们在每一次求某段栅栏最小次数时

Codeforces Round #256 (Div. 2) C. Painting Fence(分治贪心)

题目链接:http://codeforces.com/problemset/problem/448/C ---------------------------------------------------------------------------------------------------------------------------------------------------------- 欢迎光临天资小屋:http://user.qzone.qq.com/593830943

Codeforces Round #256 (Div. 2)——Painting Fence

题目连接 题意: n个木条,输入n个木条的高度,每个木条的宽度均为1.现在有长宽均为1的刷子,每次可以选择横着刷或者竖着刷,每次刷的时候不能离开木条,问将所有木条均涂色至少需要刷几次.(刷的时候可以经过已经被刷过的地方) n (1?≤?n?≤?5000),1?≤?ai(高度)?≤?109 分析: 分析一下横着和竖着的关系:假设现在已经有一个操作集合S是答案,那么集合中的操作顺序是可以改变的,即横和竖的顺序可以改变(因为可以经过已经涂色的木条),那么不妨先横着涂色.对于当前[l,r]的区间,答案不

递归解Codeforces Round #256 (Div. 2)C. Painting Fence

#include<iostream> #include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> #include<vector> #include<algorithm> using namespace std; in

Codeforces Round #256 (Div. 2) C (448C)Painting Fence

分治!首先是一大块,贪行刷和竖刷的最小,再转化为小块............ AC代码如下: #include<iostream> #include<cstring> #include<cstdio> using namespace std; int n; int a[5005]; int solve(int l,int r) { int i,j; int len=r-l+1; int height=a[l]; for(i=l;i<=r;i++) if(a[i]&

Codeforces Round #256 (Div. 2) C. Painting Fence

C. Painting Fence Bizon the Champion isn't just attentive, he also is very hardworking. Bizon the Champion decided to paint his old fence his favorite color, orange. The fence is represented as n vertical planks, put in a row. Adjacent planks have no

Painting Fence

Time Limit:1000MS     Memory Limit:524288KB     64bit IO Format:%I64d & %I64u Submit Status Description Bizon the Champion isn't just attentive, he also is very hardworking. Bizon the Champion decided to paint his old fence his favorite color, orange

#256 (Div. 2)C. Painting Fence

题意:给出篱笆的高度,宽度都是1,我们用宽度为1的刷子刷,只能横着或者竖着刷,连续的,问最少多少次全刷完 思路:我们可以全部竖着刷,N次,然后我们如果横着的话就是连续的非0数列中最短的和这个连续的数列都竖着刷比较,DFS 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=5002; 4 int a[N]; 5 6 int n; 7 8 int dfs(int l,int r){ 9 int Min=1e9+7; 10

codeforces 448C Painting Fence

刷篱笆,只有横和竖, 竖着肯定最多是 n , 另一种 那么每一次先把最下面的那个刷掉,  刷掉之后 ,  继续把上面的  刷掉,, 每一次把  剩下的   再按横着或竖着  刷 就是分治了 #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define inf 0x7f7f7f7f int a[6000]; int