「BZOJ1296」[SCOI2009]粉刷匠

Description

windy有 NN 条木板需要被粉刷。 每条木板被分为 MM 个格子。 每个格子要被刷成红色或蓝色。

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

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

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

Input

第一行包含三个整数,NN MM TT

接下来有NN行,每行一个长度为MM的字符串,0表示红色,1表示蓝色。

Output

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

Sample Input

1
2
3
4
3 6 3
111111
000000
001100

Sample Output

1
16

HINT

30%30\%的数据,满足 1N,M101 \leq N,M \leq 100T1000 \leq T \leq 100

100%100\%的数据,满足 1N,M501 \leq N,M \leq 500T25000 \leq T \leq 2500

Solution

fi,j,k,lf_{i,j,k,l}表示刷到(i,j)(i,j),刷了kk次,(i,j)(i,j)这个点刷得颜色是ll
转移显然把。分刷不同与相同两种情况,对应转移就行了。

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
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<map>
#include<bitset>
#define mk make_pair
#define fi first
#define nd second
#define pii pair<int,int>
#define pb push_back
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long ll;
inline ll read() {ll x = 0; char ch = getchar(), w = 1;while(ch < '0' || ch > '9') {if(ch == '-') w = -1;
ch = getchar();}while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}return x * w;}
void write(ll x) {if(x < 0) putchar('-'), x = -x;if(x > 9) write(x / 10);putchar(x % 10 + '0');}
inline void writeln(ll x) {write(x);puts("");}
int n, m, t;
int f[51][51][2511][2];
char s[51];
int main() {
n = read(), m = read(), t = read();
f[0][m][0][0] = f[0][m][0][1] = 0;
for(int i = 1; i <= n; ++i) {
scanf("%s", s + 1);
for(int j = 1; j <= m; ++j) s[j] -= '0';
for(int j = 1; j <= m; ++j) {
for(int k = 1; k <= t; ++k) {
if(j == 1) {
f[i][j][k][s[j]] = max(f[i - 1][m][k - 1][0], f[i - 1][m][k - 1][1]) + 1;
f[i][j][k][s[j] ^ 1] = max(f[i - 1][m][k - 1][0], f[i - 1][m][k - 1][1]);
} else {
f[i][j][k][s[j]] = max(f[i][j - 1][k - 1][s[j] ^ 1], f[i][j - 1][k][s[j]]) + 1;
f[i][j][k][s[j] ^ 1] = max(f[i][j - 1][k - 1][s[j]], f[i][j - 1][k][s[j] ^ 1]);
}
}
}
}
writeln(max(f[n][m][t][0], f[n][m][t][1]));
return 0;
}