题解 CF1391D 【505】
KellyFrog
2020-08-10 09:18:16
给出一个$n\times m$的$01$矩阵,如果每个长宽都为偶数的子矩阵内都只有奇数个$1$,则称这个矩阵是好的。
问能否把矩阵改成好的,如果能改几下。
首先证明:$m,n\ge4$时无解。
取 $(1,1)$ 到 $(2,2)$、$(1,3)$ 到 $(2,4)$、$(3,1)$ 到$(4,2)$ 和 $(3,3)$ 到 $(4,4)$ 四个子矩阵,他们中间都有奇数个 $1$,所以$(1,1)$到 $(4,4)$ 有偶数个 $1$,和好矩阵的定义矛盾,故不存在这样的好矩阵。
之后,由于 $n$ 较小,并且 $n\le m$,所以压根不用状压,直接暴力分类讨论:
1. $n=1$:输出0
2. $n=2$:令 $f_{i,a,b}$ 表示第 $i$ 列,第一个元素是 $a$,第二个元素是 $b$,让 $(1,1)$ 到 $(2,i)$ 是好矩阵的最少变动数
3. $n=3$:令 $f_{i,a,b,c}$ 表示第 $i$ 列,第一个元素是 $a$,第二个元素是 $b$,第三个元素是 $c$,让 $(1,1)$ 到 $(3,i)$ 是好矩阵的最少变动数
之后对总共的 $12$ 种情况,分别画图讨论就可以了,思维难度瞬间降低。
代码有一种宏伟的气势23333333
```cpp
#include <iostream>
using namespace std;
const int MAXNM = 1e6 + 5;
int n, m;
char mat[MAXNM << 2];
int dp[MAXNM][2][2][2];
#define str(i, j) mat[(i - 1) * m + j]
int main() {
scanf("%d%d", &n, &m);
if(n > 3 && m > 3) {
cout << -1 << endl;
}
for(int i = 1; i <= n; i++) {
scanf("%s", &str(i, 1));
}
if(n == 1) {
cout << 0 << endl;
} else if(n == 2) {
for(int i = 1; i <= m; i++) {
dp[i][1][0][0] = min(dp[i - 1][1][1][0], dp[i - 1][0][0][0]) + (str(1, i) == '0') + (str(2, i) == '1');
dp[i][0][1][0] = min(dp[i - 1][1][1][0], dp[i - 1][0][0][0]) + (str(1, i) == '1') + (str(2, i) == '0');
dp[i][0][0][0] = min(dp[i - 1][1][0][0], dp[i - 1][0][1][0]) + (str(1, i) == '1') + (str(2, i) == '1');
dp[i][1][1][0] = min(dp[i - 1][1][0][0], dp[i - 1][0][1][0]) + (str(1, i) == '0') + (str(2, i) == '0');
}
cout << min(min(dp[m][0][0][0], dp[m][0][1][0]), min(dp[m][1][0][0], dp[m][1][1][0])) << endl;
} else if(n == 3) {
for(int i = 1; i <= m; i++) {
dp[i][0][0][0] = min(dp[i - 1][1][0][1], dp[i - 1][0][1][0]) + (str(1, i) == '1') + (str(2, i) == '1') + (str(3, i) == '1');
dp[i][0][0][1] = min(dp[i - 1][1][0][0], dp[i - 1][0][1][1]) + (str(1, i) == '1') + (str(2, i) == '1') + (str(3, i) == '0');
dp[i][0][1][0] = min(dp[i - 1][1][1][1], dp[i - 1][0][0][0]) + (str(1, i) == '1') + (str(2, i) == '0') + (str(3, i) == '1');
dp[i][0][1][1] = min(dp[i - 1][1][1][0], dp[i - 1][0][0][1]) + (str(1, i) == '1') + (str(2, i) == '0') + (str(3, i) == '0');
dp[i][1][0][0] = min(dp[i - 1][0][0][1], dp[i - 1][1][1][0]) + (str(1, i) == '0') + (str(2, i) == '1') + (str(3, i) == '1');
dp[i][1][0][1] = min(dp[i - 1][1][1][1], dp[i - 1][0][0][0]) + (str(1, i) == '0') + (str(2, i) == '1') + (str(3, i) == '0');
dp[i][1][1][0] = min(dp[i - 1][1][0][0], dp[i - 1][0][1][1]) + (str(1, i) == '0') + (str(2, i) == '0') + (str(3, i) == '1');
dp[i][1][1][1] = min(dp[i - 1][0][1][0], dp[i - 1][1][0][1]) + (str(1, i) == '0') + (str(2, i) == '0') + (str(3, i) == '0');
}
int ans = 1e9 + 1;
for(int i = 0; i < 2; i++) {
for(int j = 0; j < 2; j++) {
for(int k = 0; k < 2; k++) {
ans = min(ans, dp[m][i][j][k]);
}
}
}
cout << ans << endl;
}
}
```