• 「Luogu4158」[SCOI2009]粉刷匠


    「Luogu4158」[SCOI2009]粉刷匠

    problem

    题目描述

    (windy)(N) 条木板需要被粉刷。 每条木板被分为 (M) 个格子。 每个格子要被刷成红色或蓝色。

    (windy)每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。

    如果(windy)只能粉刷 (T) 次,他最多能正确粉刷多少格子?

    一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。

    输入输出格式

    输入格式:

    第一行包含三个整数,(N) (M) (T)

    接下来有(N)行,每行一个长度为(M)的字符串,'0'表示红色,'1'表示蓝色。

    输出格式:

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

    输入输出样例

    输入样例#1:

    3 6 3
    111111
    000000
    001100
    

    输出样例#1:

    16
    

    说明

    (30\%)的数据,满足 (1 le N,M le 10)(0 le T le 100)

    (100\%)的数据,满足 (1 le N,M <= 50)(0 le T le 2500)

    Solution

    蒟蒻看到这题想了(n)多种完全不正确的处理方法,如果是在考场上估计已经光速凉凉了(QAQ)

    对于每一行,我们可以把它分成若干个颜色不同的连续段(对应若干次颜色不同的粉刷),从左到右考虑

    注意到题目:

    一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。

    意思就是不刷白不刷

    如果是颜色不对,多刷这一格不会比不刷差,就不需要考虑不刷的情况

    所以我们有:

    状态:设(dp_{i,j,k,0/1})表示当前枚举到第(i)行,第(j)个格子,已经涂了(k)次(分成了(k)段),当前格子涂的颜色是(0/1)

    方程:

    [dp_{i,j,k,x}=max(dp_{i,j-1,k,x},dp_{i,j-1,k-1,xspace xorspace 1})+[x=color_{i,j}] ]

    (方括号是艾弗森括号,当其中的条件为真时值为(1),否则为(0))

    这个转移应该很好理解吧


    处理完每一行之后,(max(dp_{i,m,k,0},dp_{i,m,k,1}))即为第(i)行分配(k)次粉刷次数所能正确粉刷的最大格子数

    这样,每一行作为一组,原问题就转化为一个分组背包问题,在此不再赘述

    Code

    代码中所用的字母与上述转移方程略有不同,请注意辨别

    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #define maxn 55
    #define maxm 55
    #define maxt 2505
    using namespace std;
    typedef long long ll;
    
    template <typename T> void read(T &t)
    {
    	t=0;int f=0;char c=getchar();
    	while(!isdigit(c)){f|=c=='-';c=getchar();}
    	while(isdigit(c)){t=t*10+c-'0';c=getchar();}
    	if(f)t=-t;
    }
    
    int n,m,t;
    int col[maxn][maxm];
    int dp[maxn][maxm][maxm][2],tdp[maxt];
    
    int main()
    {
    	read(n),read(m),read(t);
    	for(register int i=1;i<=n;++i)
    	{
    		char c[maxm];
    		scanf("%s",c+1);
    		for(register int j=1;j<=m;++j)
    			col[i][j]=c[j]-'0';
    	}
    	for(register int li=1;li<=n;++li)
    		for(register int i=1;i<=m;++i)
    			for(register int k=1;k<=min(t,m);++k)
    				for(register int x=0;x<=1;++x)
    					dp[li][i][k][x]=max(dp[li][i-1][k][x],dp[li][i-1][k-1][x^1])+(x==col[li][i]);
    	for(register int i=1;i<=n;++i)
    		for(register int j=t;j>=0;--j)
    			for(register int k=1;k<=min(j,m);++k)
    				tdp[j]=max(tdp[j],tdp[j-k]+max(dp[i][m][k][0],dp[i][m][k][1]));
    	printf("%d",tdp[t]);
    	return 0;
    }
    
  • 相关阅读:
    Windows Service 2016 DatacenterStandEmbedded激活方法
    批处理文件设置IP以及DNS
    C#类的一些基础知识(静态方法可以不用实例化调用)
    Dynamics Crm Plugin插件注册的问题及解决方案(持续更新。。。。。。)
    【转载】C# get 与set的一些说明
    C#补位函数PadLeft和PadRight
    Kubernetes集群调度之Scheduler
    Kubernetes集群控制之ControllerManager
    Kubernetes集群大脑之apiserver
    Kubernetes集群存储之etcd
  • 原文地址:https://www.cnblogs.com/lizbaka/p/10417671.html
Copyright © 2020-2023  润新知