• cf 448c Painting Fence


    http://codeforces.com/problemset/problem/448/C


    题目大意:给你一个栅栏,每次选一横排或竖排染色,求把全部染色的最少次数,一个点不能重复染色。
    这道题有点像,不过可以竖着。
    考虑横着涂一次的情况,那么有两个显而易见的事实。

    1.这次涂色长度必须尽可能大。
    2.在这次涂色区域的下方,必定都是横着涂的。

    所以,对于一串栅栏h 1 , h 2 , ... , h n ,如果要横着涂,就必定要从底向上涂min⁡{h 1 , h 2 , ... , h n }次。这样以后,h 1 , h 2 , ... , h n 就会分成若干不连通的子局面。
    那么显然可以设计一个分治的算法,时间复杂度为O(N 2 ):
    (Solve(l, r, h))代表([l, r])这段栅栏,已经从下向上涂了h格的答案。
    (h'= min⁡{h_1, h_2 , ... , h_n }),那么:
    (Solve(l, r, h) = ⁡min{⁡r - l + 1, sum solve(u, v, h')⁡|⁡[u, v]为分割出的子局面⁡⁡})
    边界情况:l = r 时,答案显然为 1。
    以后static不能乱用(在递归中),,,

    // It is made by XZZ
    #include<cstdio>
    #include<algorithm>
    #define Fname "color"
    using namespace std;
    #define rep(a,b,c) for(rg int a=b;a<=c;a++)
    #define drep(a,b,c) for(rg int a=b;a>=c;a--)
    #define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
    #define il inline
    #define rg register
    #define vd void
    typedef long long ll;
    il ll gi(){
        rg ll x=0;bool flg=0;rg char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')flg=1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return flg?-x:x;
    }
    ll n,h[5010];
    il ll Doit(ll l,ll r,ll _h){
    	if(l==r)return 1;
    	ll m=2e18;
    	rep(i,l,r)m=min(m,h[i]);
    	ll ans=m-_h;
    	rep(i,l,r)
    		if(h[i]!=m){
    			ll j;j=i;
    			while(j!=r&&h[j+1]!=m)++j;
    			ans+=Doit(i,j,m),i=j+1;
    		}
    	return min(ans,r-l+1);
    }
    int main(){
        freopen(Fname".in","r",stdin);
        freopen(Fname".out","w",stdout);
    	n=gi();
    	rep(i,1,n)h[i]=gi();
    	printf("%lld
    ",Doit(1,n,0));
        return 0;
    }
    
  • 相关阅读:
    hdu1251统计难题(trie树)
    线段树
    poj2632Crashing Robots
    UVA10194 Football (aka Soccer)
    hdu1166敌兵布阵(线段树)
    【洛谷P3810】【模板】三维偏序(陌上花开)
    【洛谷P2480】古代猪文
    【洛谷P3449】PALPalindromes
    【洛谷P4777】扩展中国剩余定理(EXCRT)
    【洛谷P2421】荒岛野人
  • 原文地址:https://www.cnblogs.com/xzz_233/p/cf-448-c.html
Copyright © 2020-2023  润新知