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

转载于:https://www.cnblogs.com/xzz_233/p/cf-448-c.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值