bzoj 1296 [SCOI2009]粉刷匠

来源:互联网 发布:智慧记mac版下载 编辑:程序博客网 时间:2024/04/29 01:00

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

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

Output
输出文件paint.out包含一个整数,最多能正确粉刷的格子数。

Sample Input
3 6 3
111111
000000
001100

Sample Output
16

HINT
30%的数据,满足 1 <= N,M <= 10 ; 0 <= T <= 100 。 100%的数据,满足 1 <= N,M <= 50 ; 0 <= T <= 2500 。

Solution

我们先一行一行考虑,s[j][k]表示某行最远刷到j,用了k次的最大值。
然后我们可以借助s数组来生成w[k]表示该行刷k次的最大值
就可以像背包一样更新了。

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#define ll long longusing namespace std;int n,m,t;char a[55][55];int f[2505],w[2505];int zero[55],s[55][2505];int main(){    cin>>n>>m>>t;    for(int i=1;i<=n;i++)     {        memset(w,0,sizeof(w));        memset(s,0,sizeof(s));        scanf("%s",a[i]+1);        for(int j=1;j<=m;j++) zero[j]=zero[j-1]+(a[i][j]=='0');        for(int j=1;j<=m;j++)         for(int k=1;k<=t;k++)         {            for(int pre=0;pre<j;pre++)             s[j][k]=max(s[j][k],s[pre][k-1]+max(zero[j]-zero[pre],j-pre-zero[j]+zero[pre]));            w[k]=max(w[k],s[j][k]);        }        for(int j=t;j>=1;j--)         for(int k=1;k<=j;k++)         f[j]=max(f[j],f[j-k]+w[k]);    }    cout<<f[t];    return 0;}

这个程序美中不足的是,求s的过程最多达到505,有TLE的危险。
我们考虑如何优化s的求法。
上述算法为什么要枚举pre?因为我在状态里没有确定颜色,如果我确定了颜色,我就可以直接从j-1的位置转移了。

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#define ll long longusing namespace std;int n,m,t;char a[55][55];int f[2505],w[2505];int zero[55],s[55][2505][2];int main(){    cin>>n>>m>>t;    for(int i=1;i<=n;i++)     {        memset(w,0,sizeof(w));        memset(s,0,sizeof(s));        scanf("%s",a[i]+1);        for(int j=1;j<=m;j++) zero[j]=zero[j-1]+(a[i][j]=='0');        for(int j=1;j<=m;j++)         for(int k=1;k<=t;k++)         {            s[j][k][0]=max(s[j-1][k][0],s[j-1][k-1][1])+(a[i][j]=='0');            s[j][k][1]=max(s[j-1][k][1],s[j-1][k-1][0])+(a[i][j]=='1');            w[k]=max(w[k],s[j][k][0]);            w[k]=max(w[k],s[j][k][1]);        }        for(int j=t;j>=1;j--)         for(int k=1;k<=j;k++)         f[j]=max(f[j],f[j-k]+w[k]);    }    cout<<f[t];    return 0;}
0 0
原创粉丝点击