【题解】CF1592F-Alice and Recoloring

很神的思维题。

观察以下发现对于矩阵取反非常不好做。

这时候我们可以联想到差分,将它转化为单点取反。

所以我们构造广义差分数组 \(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;
}

上一篇:Element-ui的表单中怎么添加正则校验


下一篇:21.10.27模拟 solve