很神的思维题。
观察以下发现对于矩阵取反非常不好做。
这时候我们可以联想到差分,将它转化为单点取反。
所以我们构造广义差分数组 \(a_{i,j} = s_{i,j}\oplus s_{i+1,j}\oplus s_{i,j + 1}\oplus s_{i+1,j + 1}\)。原矩阵 \(s\) 全 \(0\) 等价于矩阵 \(a\) 全 \(0\)。
手算以下发现 \(1,2,3\) 操作对应单点取反,\(4\) 操作对应 \(4\) 个点取反。
所以对于 \(F1\) 题,\(4\) 操作最多只会进行一次,枚举以下即可。
对于 \(F2\) 题,一个位置除了 \((n,m)\) 只会翻转一次,且尽量先用 \(4\) 操作,所以直接套二分图模型即可。
#define N 505
int n, m, a[N][N], u[N][N]; char s[N];
int main() {
//int T = read();while(T--)solve();
n = read(), m = read();
rep(i, 1, n){
scanf("%s", s + 1);
rep(j, 1, m)a[i][j] = s[j] == 'B';
}
int ans = 0;
rep(i, 1, n)rep(j, 1, m)ans += (u[i][j] = a[i][j] ^ a[i + 1][j] ^ a[i][j + 1] ^ a[i + 1][j + 1]);
if(u[n][m])
rep(i, 1, n - 1)rep(j, 1, m - 1)if(u[i][j] && u[n][j] && u[i][m]){
printf("%d\n", ans - 1);return 0;
}
printf("%d\n", ans);
return 0;
}
#define N 505
int n, m, u[N][N], a[N][N], s, t; char w[N];
int h[N << 1], tot = 1, d[N << 1], cur[N << 1];
struct edge{int to, nxt, cap;}e[N * N * 4];
void add(int x,int y,int z){
e[++tot].nxt = h[x], h[x] = tot, e[tot].to = y, e[tot].cap = z;
e[++tot].nxt = h[y], h[y] = tot, e[tot].to = x, e[tot].cap = 0;
}
queue<int>q;
bool bfs(){
memset(d, 0, sizeof(d));
d[s] = 1, q.push(s);
while(!q.empty()){
int x = q.front(); q.pop(); cur[x] = h[x];
for(int i = h[x]; i; i = e[i].nxt)if(e[i].cap && !d[e[i].to])
d[e[i].to] = d[x] + 1, q.push(e[i].to);
}
return d[t] ? 1 : 0;
}
int dfs(int x,int flow){
if(t == x)return flow;
int res = flow;
for(int &i = cur[x]; i; i = e[i].nxt) if(e[i].cap && d[x] + 1 == d[e[i].to]){
int now = dfs(e[i].to, min(res, e[i].cap));
if(!now)d[e[i].to] = 0;
else e[i].cap -= now, e[i ^ 1].cap += now, res -= now;
if(!res)return flow;
}
return flow - res;
}
int main() {
//int T = read();while(T--)solve();
n = read(), m = read();
rep(i, 1, n){
scanf("%s", w + 1);
rep(j, 1, m)a[i][j] = w[j] == 'B';
}
int ans = 0;
rep(i, 1, n)rep(j, 1, m)ans += (u[i][j] = a[i][j] ^ a[i + 1][j] ^ a[i][j + 1] ^ a[i + 1][j + 1]);
rep(i, 1, n - 1)rep(j, 1, m - 1)if(u[i][j])add(i, j + n - 1, 1);
s = n + m - 1, t = s + 1;
rep(i, 1, n - 1)if(u[i][m])add(s, i, 1);
rep(i, 1, m - 1)if(u[n][i])add(i + n - 1, t, 1);
int sum = 0;
while(bfs())sum += dfs(s, n + m);
if(sum)printf("%d\n", ans - sum + ((sum & 1) ^ u[n][m]) - u[n][m]);
else printf("%d\n", ans);
return 0;
}