ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P4158 [SCOI2009]粉刷匠

2020-12-09 20:32:59  阅读:238  来源: 互联网

标签:int ll memset 粉刷 55 SCOI2009 涂色 sizeof P4158


题目链接

我们不妨先考虑只有一行的情形。

我们做两个前缀和\(red_i,bule_i\)分别表示前\(i\)个里有多少个红色块和蓝色块。

设\(f[i][k]\)为做到第\(i\)块,此时用了\(k\)次涂刷的最大收益。

我们思考如下问题:既然重复涂色没有收益,那么我们强制让我们的涂色方案没有重叠的情况,即让我们对于这一行的方案如下图:

可以看出一段木块被分割成若干块(无色代表没涂色。

我们只要从\(i\)向前枚举上一段的终点在哪即可转移,对于\(i\)这块不涂色的情况我们直接拿\(i - 1\)的答案来覆盖即可

所以对于一条木块我们有了\(O(m^3)\)的做法来求出\(f\)

		for(int r = 1;r <= m;++r){
			for(int k = 1;k <= m;++k){
				f[r][k] = f[r - 1][k];
				for(int l = 1;l <= r;++l){
					f[r][k] = std::max(f[l - 1][k - 1] + red[r] - red[l - 1],f[r][k]);
					f[r][k] = std::max(f[l - 1][k - 1] + bule[r] - bule[l - 1],f[r][k]);	
				}
			}
		}

我们接下来考虑我们做完了一条木块怎么统计答案:

	 	for(int to = t;to >= 0;-- to)
	 	for(int k = 0;k <= std::min(m,(ll)to);++k)
	 	fans[to] = std::max(fans[to],fans[to - k] + f[m][k]),ans = std::max(ans,fans[to]); 

类似于一维背包即可。(注意枚举\(k\)时不要超出数组\(f\)的大小,因为这个我调了好久)

所以最后的复杂度是\(O(n * (m ^ 3 + tm))\)

喜闻乐见的代码环节

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long

ll n,m,t,ans = 0,f[55][55];
ll red[55],bule[55];
ll fans[2505];

void init(){
	memset(f,0,sizeof(f));
	memset(red,0,sizeof(red));
	memset(bule,0,sizeof(bule));
}

int main(){
//	freopen("q.in","r",stdin);
//	freopen("q.out","w",stdout);
	memset(fans,0,sizeof(fans));
	scanf("%lld%lld%lld",&n,&m,&t);
	for(int i = 1;i <= n;++i){
		init();
		char s[55];
		scanf("%s",s + 1);
		for(int i = 1;i <= m;++i){
			red[i] = red[i - 1];
			bule[i] = bule[i - 1];
			if(s[i] == '0')
			red[i] ++ ;
			else
			bule[i] ++ ;
		}
		for(int r = 1;r <= m;++r){
			for(int k = 1;k <= m;++k){
				f[r][k] = f[r - 1][k];
				for(int l = 1;l <= r;++l){
					f[r][k] = std::max(f[l - 1][k - 1] + red[r] - red[l - 1],f[r][k]);
					f[r][k] = std::max(f[l - 1][k - 1] + bule[r] - bule[l - 1],f[r][k]);	
				}
			}
		}
//		for(int i = 1;i <= m;++i,puts(""))
//		for(int k = 1;k <= m;++k)
//		std::cout<<f[i][k]<<" ";
	 	for(int to = t;to >= 0;-- to)
	 	for(int k = 0;k <= std::min(m,(ll)to);++k)
	 	fans[to] = std::max(fans[to],fans[to - k] + f[m][k]),ans = std::max(ans,fans[to]); 
	}
	std::cout<<ans<<std::endl; 
}
 

标签:int,ll,memset,粉刷,55,SCOI2009,涂色,sizeof,P4158
来源: https://www.cnblogs.com/dixiao/p/14110760.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有