「SCOI2009」粉刷匠

周政是个粉刷匠,粉刷本领强!他把自己的小白脸,刷得黑又脏!

传送门

洛谷P4158

BZOJ1296

题解

本蒟蒻难得1A的省选题,虽然很老。

瞅了一眼数据范围,挺小的,直接上DP瞎搞!!!(汗

设$F[i][j][k]​$表示对于第$i​$行的前$j​$列,涂了$k​$次颜料,最多能刷对几个格子。

那么初始值$F[i][j][k]=F[i][j-1][k]​$;

转移方程:

第一个式子表示$[l+1,j]$涂蓝色,第二个表示涂红色。

上式中的$sum[i][j]$表示第$i$行前$j$个格子中有几个希望被染成蓝色,即颜色的前缀和。

所以$F[i][m][k]​$就表示第$i​$行涂$k​$次最多能涂对几个格子。

预处理出了上式之后,然后再DP一趟,就能得出答案了呢(雾

令$G[i][j]​$表示对于前$i​$行,涂了$j​$次颜料,最多能涂对多少个格子。

那么很显然又有转移方程:

这趟DP刷完之后,终于得到了答案,即$G[n​$][T]。

就没有然后了QwQ

代码

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
#include<cstdio>
using namespace std;
const int maxn=55,maxt=2505;
int n,m,T,F[maxn][maxn][maxn],sum[maxn][maxn],G[maxn][maxt];
char GetChar()
{
char ch=getchar();
while(ch!='0'&&ch!='1') ch=getchar();
return ch;
}
int main()
{
scanf("%d%d%d",&n,&m,&T);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
sum[i][j]=sum[i][j-1]+(int)(GetChar()=='1');
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=1;k<=m;k++)
{
F[i][j][k]=F[i][j-1][k];
for(int l=0;l<j;l++)
{
if(F[i][l][k-1]+sum[i][j]-sum[i][l]>F[i][j][k]) F[i][j][k]=F[i][l][k-1]+sum[i][j]-sum[i][l];
if(F[i][l][k-1]+j-l-sum[i][j]+sum[i][l]>F[i][j][k]) F[i][j][k]=F[i][l][k-1]+j-l-sum[i][j]+sum[i][l];
}
}
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=T;j++)
for(int k=0;k<=m&&k<=j;k++)
if(G[i-1][j-k]+F[i][m][k]>G[i][j])
G[i][j]=G[i-1][j-k]+F[i][m][k];
printf("%d\n",G[n][T]);
return 0;
}