洛谷-4158 [SCOI2009]粉刷匠

题目描述
windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。
windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。
如果windy只能粉刷 T 次,他最多能正确粉刷多少格子?
一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。

输入格式
第一行包含三个整数,N M T。
接下来有N行,每行一个长度为M的字符串,'0’表示红色,'1’表示蓝色。

输出格式
包含一个整数,最多能正确粉刷的格子数。

输入输出样例
输入 #1复制
3 6 3
111111
000000
001100

输出 #1复制
16

说明/提示
30%的数据,满足 1 <= N,M <= 10 ; 0 <= T <= 100 。
100%的数据,满足 1 <= N,M <= 50 ; 0 <= T <= 2500 。

解释:两次dp,首先处理出每行, d p [ i ] [ j ] [ 0 / 1 ] : dp[i][j][0/1]: dp[i][j][0/1]:从1-i,涂j种颜色,且最后一种为0/1的最多正确格子,转移的话…
最后我们再$ret[i][j]:$1-i行,用了j次最小多少,最后我们可以统计答案

#include<iostream>
#include<cstring>
#include<cstdio>
#define min(x,y) x>y?y:x
#define inf 1000000009
using namespace std;
long long n=0,m=0,t=0;
char G[103];
long long a[53][53]={0};
long long dp[53][2503][2]={0};
long long ret[53][2503]={0};
int main(){
    ios::sync_with_stdio(false);
    scanf("%lld%lld%lld",&n,&m,&t);
    for(int ii=1;ii<=n;ii++){
        memset(dp,0,sizeof(dp));
        scanf("%s",G+1);
        for(int i=1;i<=m;i++){
            for(int j=1;j<=t;j++){
                for(int k=0;k<2;k++){
                    if(G[i]==G[i-1]){
                        if(G[i]==k+'0'){
                            dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k]+1);
                        }else{
                            dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k]);
                        }
                    }else{
                        if(G[i]==k+'0'){
                            dp[i][j][k]=max(dp[i][j][k],max(dp[i-1][j][k]+1,dp[i-1][j-1][1-k]+1));
                        }else{
                            dp[i][j][k]=max(dp[i][j][k],max(dp[i-1][j][k],dp[i-1][j-1][1-k]));
                        }
                    }
                }
            }
        }
        for(int j=1;j<=t;j++){
            a[ii][j]=m-max(dp[m][j][0],dp[m][j][1]);
        }
        a[ii][0]=m;
    }
    for(int i=1;i<=n;i++) for(int j=0;j<=t;j++) ret[i][j]=inf;
    long long ans=inf;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=t;j++){
            for(int k=0;k<=j;k++){
                ret[i][j]=min(ret[i][j],ret[i-1][j-k]+a[i][k]);
            }
        }
    }
    for(int i=0;i<=t;i++) ans=min(ans,ret[n][i]);
    printf("%lld\n",n*m-ans);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值