【題解】CF1592F-Alice and Recoloring
阿新 • • 發佈:2021-11-08
很神的思維題。
觀察以下發現對於矩陣取反非常不好做。
這時候我們可以聯想到差分,將它轉化為單點取反。
所以我們構造廣義差分陣列 \(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; }