abc 264 f 题解
abc 264 f
题意
有一个 \(N \times M\) 的矩阵,每个格子是黑色或者白色的。
如果 \(A_{i, j} = 0\),格子 \((i, j)\) 是白色的,否则,格子 \((i, j)\) 是黑色的。
可以按顺序执行以下操作若干次:
-
选择一个整数 \(i \ (1 \le i \le N)\),用 \(R_i\) 的代价将第 \(i\) 行的所有格子的颜色取反。
-
选择一个整数 \(j \ (i \le j \le M)\),用 \(C_j\) 的代价将第 \(j\) 列的所有格子的颜色取反。
请求出满足以下要求的最小代价:
- 在矩阵上只能向右或者向下走。存在一条从格子 \((1, 1)\) 到格子 \((N, M)\) 的路径,使得路径上的所有格子颜色相同。
思路
首先,可以肯定的是,每一行或者每一列都最多只会被取反一次,如果取反两次,那么就会变回原来的样子,白白浪费了很多代价。
那么,就可以想到一种状态:\(dp_{x, y, 0 / 1, 0 / 1}\) 表示走到 \((x, y)\) 且第 \(x\) 行翻或不翻,第 \(y\) 列翻或不翻时的最小代价。
我们可以通过异或操作得到往右走是否需要翻转下一列以及往下走是否需要翻转下一行,进行转移即可。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2010, M = N;
int n, m, r[N], c[M];
long long dp[N][M][2][2], ans = 9e18;
bool a[N][M];
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> r[i];
}
for (int i = 1; i <= m; i++) {
cin >> c[i];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
char ch;
cin >> ch, a[i][j] = ch - '0';
for (int k = 0; k < 2; k++) {
for (int l = 0; l < 2; l++) {
dp[i][j][k][l] = 9e18;
}
}
}
}
for (int k = 0; k < 2; k++) {
for (int l = 0; l < 2; l++) {
dp[1][1][k][l] = k * r[1] + l * c[1];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
for (int k = 0; k < 2; k++) {
for (int l = 0; l < 2; l++) {
int z = a[i][j] ^ l ^ a[i][j + 1];
dp[i][j + 1][k][z] = min(dp[i][j + 1][k][z], dp[i][j][k][l] + z * c[j + 1]);
z = a[i][j] ^ k ^ a[i + 1][j];
dp[i + 1][j][z][l] = min(dp[i + 1][j][z][l], dp[i][j][k][l] + z * r[i + 1]);
if (i == n && j == m) {
ans = min(ans, dp[i][j][k][l]);
}
}
}
}
}
cout << ans;
return 0;
}