• 刷题记录:牛客NC20273[SCOI2009]粉刷匠


    传送门:牛客

    题目描述:

    windy有 N 条木板需要被粉刷。 每条木板被分为 M 个格子。 每个格子要被刷成红色或蓝色。 
    windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色。 每个格子最多只能被粉刷一次。 
    如果windy只能粉刷 T 次,他最多能正确粉刷多少格子? 
    一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷。
    输入:
    3 6 3
    111111
    000000
    001100
    输出:
    16
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    仅以此题作为我简单dp学习的终止符

    主要思路:

    1. 对于此题,我们要将二维的矩阵问题分成两个一维的情况来做,我们先求出对于每一条木条花费 K K K次能正确粉刷多少格子.假设我们已经求出了上述问题,那么我们会发现,对于每一根木条,我们都有一个m种花费,并且对于每一种花费都有对应的贡献.我们会惊奇的发现我们现在就是一个简单的分组背包问题而已.我擦,这道看起来很难解决的问题就这么被巧妙的解决了
    2. 那么对于我们的每一条木条该怎么维护呢.其实假设这种区间dp的题目做的多的话,应该会有一个朴素的dp方程,使用 d p [ i ] [ j ] [ k ] 来 维 护 第 i 根 木 条 前 j 个 位 置 涂 了 k 次 能 正 确 粉 刷 多 少 格 子 dp[i][j][k]来维护第i根木条前j个位置涂了k次能正确粉刷多少格子 dp[i][j][k]ijk,那么我们应该会有一个经典的转移方程,那就是在当前位置之前枚举涂了 k − 1 k-1 k1次的位置,那么此时我们的贡献就是 k − 1 k-1 k1的贡献加上最后一次粉刷的贡献了,对于最后一次粉刷的贡献,我们可以在跑之前维护出每一段区间的贡献值即可.
    3. 对于每一段区间的贡献值,我们可以使用前缀和的方式进行维护,因为我们的颜色只有0和1,这样的话使用前缀和就在合适不过了.

    下面是具体的代码部分:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    typedef long long ll;
    #define inf 0x3f3f3f3f
    #define root 1,n,1
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    inline ll read() {
    	ll x=0,w=1;char ch=getchar();
    	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    	return x*w;
    }
    #define maxn 1000000
    #define ll_maxn 0x3f3f3f3f3f3f3f3f
    const double eps=1e-8;
    int n,m,t;
    int huafei[60][60][60];
    int f[maxn];int sum[100][100];
    int main() {
    	n=read();m=read();t=read();
    	string num;
    	for(int i=1;i<=n;i++) {
    		cin>>num;
    		for(int j=0;j<num.length();j++) {
    			sum[i][j+1]=sum[i][j]+num[j]-'0';
    		}
    	}
    	for(int i=1;i<=n;i++) {
    		for(int j=1;j<=m;j++) {
    			huafei[i][j][1]=max(sum[i][j],j-sum[i][j]);
    		}
    	}
    	for(int i=1;i<=n;i++) {
    		for(int j=1;j<=m;j++) {
    			for(int k=2;k<=j;k++) {
    				for(int x=k-1;x<j;x++) {
    					int leijia=max(sum[i][j]-sum[i][x],j-x-(sum[i][j]-sum[i][x]));
    					huafei[i][j][k]=max(huafei[i][j][k],huafei[i][x][k-1]+leijia);
    				}
    			}
    		}
    	}
    	for(int i=1;i<=n;i++) {
    		for(int j=t;j>=0;j--) {
    			for(int num=1;num<=m;num++) {
    				if(j<num) break;
    				f[j]=max(f[j],f[j-num]+huafei[i][m][num]);
    			}
    		}
    	}
    	cout<<f[t]<<endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
  • 相关阅读:
    2024年网络安全/黑客自学路线图
    在winform中如何嵌入第三方软件窗体✨
    大模型实战提示工程 1—常用的大语言模型参数说明
    [模版总结] - 树的基本算法3 - 结构转化
    文举论金:黄金原油全面走势分析策略独家指导
    以程序员的身份使用curl获取速卖通详情
    黑龙江省等保评测常用的安全设备,看这一篇就够了
    java数据结构(红黑树)set集合 HashSet HashSet三个问题 LinkedHashSetTreeSet TreeSet集合默认规则排序规则
    【Leetcode】964. Least Operators to Express Number
    同步时序逻辑电路
  • 原文地址:https://blog.csdn.net/yingjiayu12/article/details/127915648