100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > .7.8模拟赛【笨笨当粉刷匠】|bzoj1296 [SCOI]粉刷匠

.7.8模拟赛【笨笨当粉刷匠】|bzoj1296 [SCOI]粉刷匠

时间:2020-02-26 13:58:39

相关推荐

.7.8模拟赛【笨笨当粉刷匠】|bzoj1296 [SCOI]粉刷匠

笨笨太好玩了,农田荒芜了,彩奖用光了,笨笨只好到处找工作,笨笨找到了一份粉刷匠的工作。笨笨有n条木板需要被粉刷。每条木板被分成m个格子,每个格子要被刷成红色或蓝色。笨笨每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色,已知每个格子最多只能被粉刷一次。

如果笨笨只能粉刷t次,他最多能正确粉刷多少格子。

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

【输入格式】

第一行三个数n,m,t;

接下来n行,每行一个长度为m的字符“0”表示红色,"1"表示蓝色。

【输出格式】

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

Sample input

3 6 3

111111

000000

001100

Sample output

16

100%数据范围满足1≤n,m≤50;0≤t≤2500。

这是bzoj上原题啊……bzoj1296 [SCOI]粉刷匠

就是两个dp

首先,注意到每一行的状态都是和其他行独立的,也就是说,只要你知道了这一行的状态,其他行长什么样无所谓。

所以我们可以先把每一行分开处理

令s[i][j][0/1]表示第i行前j个有多少个0/1。

g[i][j][k]表示第i行前j个涂k次能正确涂色的格子个数。

则g[i][j][k] = max( g[i][j][k] , g[i][L][k-1]+max(s[i][j][0] - s[i][L][0],s[i][j][1] - s[i][L][1]))。

意思是枚举第k-1次涂到L时,在L到j之间涂0或1是否比当前优,效率n^4。我曾经尝试写n^3求第i行涂j次的最优解,可惜貌似不行。

最后发现再令h[i][j]表示第i行涂j次的最优解,f[i][j]表示前i行涂j次的最优解,则f[i][j]=max(f[i][j] , f[i-1][j-k] + h[i][k])。但是边界范围要考虑,可以一整行都不刷。否则在bzoj上能A,但是模拟赛上只有90。

#include<cstdio>#include<iostream>using namespace std;char ch;int n,m,t;int h[101][101];int g[101][101][101];int s[101][101][2];int f[101][3001];bool map[101][101];int main(){freopen("draw.in","r",stdin);freopen("draw.out","w",stdout);scanf("%d%d%d",&n,&m,&t);for (int i=1;i<=n;i++)for (int j=1;j<=m;j++){cin>>ch;if (ch=='1') map[i][j]=1;s[i][j][0]=s[i][j-1][0]+(ch=='0');s[i][j][1]=s[i][j-1][1]+(ch=='1');}for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)for (int k=1;k<=m;k++)for (int l=0;l<j;l++)g[i][j][k]=max(g[i][j][k],g[i][l][k-1]+max(s[i][j][0]-s[i][l][0],s[i][j][1]-s[i][l][1]));for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)for (int k=1;k<=m;k++)h[i][j]=max(h[i][j],g[i][k][j]);for (int i=1;i<=n;i++)for (int j=1;j<=t;j++)for (int k=0;k<=j;k++)f[i][j]=max(f[i][j],f[i-1][j-k]+h[i][k]);printf("%d",f[n][t]);}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。