题目链接https://ac.nowcoder.com/acm/problem/20273

首先我们把这个问题分成两个子问题,然后分别对两个子问题求解,从而解决一个复杂的问题。

我们先来看第一个子问题:
这个子问题比较简单,就是仿照题目的,但是这个子问题里只有一条木板,即给你一条木板,上面有连续的格子,你能涂次求,求涂次的情况下最多能粉刷正确多少个格子

然后我们来看第二个子问题
我们可以把他想象成以下的模型,你要在个商店中买东西,每个商店只能买一件物品(可以不买),你有元的钱,
每个商店有种商品,每一件商品的价格为,价值为,问你花费最多元,可以获得商品的价值最大为多少

我们来将两个问题结合一下,那么我们用第一个子问题求出每个木板涂 的次数,那么对应的涂的次数就是第二问中商品的价格,粉刷正确的格子个数就是第二问中商品的价值。
第二问求出的最大价值就是题目所求的最大正确粉刷格子数

这两个问题都是经典的dp问题,我们先来看第一个
开一个三维的dp数组, 第一维表示涂到第几个格子,第二维表示涂的次数,第三维表示当前涂的是还是
转移方程很显然是从前一个继续涂或者重新开始涂转移过来

如果这一个涂对了就要对对应涂对的状态,比如当前是就要对

对于第二个问题就是经典的背包问题,这里就不多讲了

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int dp[55][55][2];
int dp2[55][2505];
char s[55];
int n,m,t;
vector<int> v[55];//v[i][j]表示第i个木板涂j次最大粉刷正确的格子数

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m>>t;
    for(int x=1;x<=n;x++)
    {
        cin>>s+1;
        for(int i=1;i<=m;i++)
            s[i]-='0';
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=i;j++)
            {
                dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j-1][1]);
                dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][0]);
                dp[i][j][s[i]]++;//涂对了
            }
        }
        v[x].push_back(0);
        for(int i=1;i<=m;i++)
        {
            v[x].push_back(max(dp[m][i][0],dp[m][i][1]));
        }
    }

    for(int i=1;i<=50;i++)
    {
        for(int j=0;j<=t;j++)
        {
            for(int k=0;k<=min((int)v[i].size()-1,j);k++)
            {
                dp2[i][j]=max(dp2[i][j],dp2[i-1][j-k]+v[i][k]);
            }
        }
    }

    cout<<dp2[n][t]<<endl;

    return 0;
}