bzoj 1296 [SCOI2009]粉刷匠

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
#include
#include
#include
#define ll long long
using 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;pre1]+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<return 0;
}

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

#include
#include
#include
#include
#define ll long long
using 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<return 0;
}

你可能感兴趣的:(bzoj)