[SCOI2009]粉刷匠 [动态规划]

[BZOJ1296] [luoguP4158]

第一眼没看出来emmm...

所以就先想只有一条木板怎么做 即\(f[i][j]\)表示前\(i\)个格子刷\(j\)次最多能刷正确多少个格子

然后很容易就能想到n条木板就可以将其进行01背包来算最多能刷正确有多少个格子

因为每个格子最多刷一次 所以枚举\(j\)\(j\)得小于等于\(i\)

#include<bits/stdc++.h>
using namespace std;
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
const int N=50+5,M=2500+5,inf=0x3f3f3f3f,P=19650827;
int n,m,t,ans=0,sum[N],f[N][M],nw[N][N];
char S[N];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int main(){
    freopen("in2.txt","r",stdin);
    //freopen("xor.out","w",stdout);
    rd(n),rd(m),rd(t);
    memset(f,0,sizeof(f));
    for(int x=1;x<=n;++x){
        scanf("%s",S+1);
        for(int i=1;i<=m;++i) sum[i]=sum[i-1]+(S[i]=='1');
        for(int i=1;i<=m;++i)//前i个格子 
        for(int j=1;j<=i;++j){//涂j次
            nw[i][j]=0;
            for(int k=0;k<i;++k)//由前k个格子转移过来 
                nw[i][j]=Max(nw[i][j],nw[k][j-1]+Max(sum[i]-sum[k],i-k-(sum[i]-sum[k])));
        }
        for(int i=1;i<=t;++i)
        for(int j=1;j<=Min(i,m);++j)
        f[x][i]=Max(f[x][i],f[x-1][i-j]+nw[m][j]);
    }
    for(int i=1;i<=t;++i) ans=Max(ans,f[n][i]);
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lxyyyy/p/11389356.html