1. 程式人生 > 其它 >【題解】CF1592F-Alice and Recoloring

【題解】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;
}