CF1592F2 Alice and Recoloring 2 题解

操作 $2,3$ 可以用 $1,4$ 容斥,所以没用。

设 $b_{i,j}=a_{i,j}\oplus a_{i+1,j}\oplus a_{i,j+1}\oplus a_{i+1,j+1}$,

则操作 $1$ 翻转 $(1,1)$ 到 $(i,j)$ 的矩阵等价于 $b_{i,j}\gets b_{i,j}\oplus 1$,

操作 $4$ 翻转 $(i,j)$ 到 $(n,m)$ 的矩阵等价于 $b_{n,m}\gets b_{n,m}\oplus 1,b_{i-1,m}\gets b_{i-1,m}\oplus 1,b_{n,j-1}\gets b_{n.j-1}\oplus 1,b_{i-1,j-1}\gets b_{i-1,j-1}\oplus 1$。

注意到所有操作 $4$ 的 $i$ 一定互不相同且 $j$ 一定互不相同,否则不如操作 $1$。

则问题转化为求最多能找出多少 $(i,j)$ 满足 $i$ 互不相同,$j$ 互不相同且 $b_{i,j}=b_{i,m}=b_{n,j}=1$。

以 $i\in[1,n)$ 为左半部,$j\in[1,m)$ 为右半部建二分图,存在 $i\to j$ 当且仅当 $b_{i,j}=b_{i,m}=b_{n,j}=1$,则该图的最大匹配即为操作 $4$ 的个数 $p$。

一次操作 $4$ 可以省一次操作 $1$,所以这些操作 $4$ 的贡献是 $-p$。

注意 $p$ 为奇数时要特判 $b_{n,m}$ 的值,

若 $b_{n,m}=0$ 则经过这些操作 $4$ 后 $b_{n,m}$ 变为 $1$,需要一个额外的操作 $1$。

若 $b_{n,m}=1$ 则经过这些操作 $4$ 后 $b_{n,m}$ 变为 $0$,可以省一个操作 $1$。

#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
struct E{int v, w, t;}e[250050];
int n, m, r, p, c = 1, s, t, d[1050], g[1050], h[1050];
bool a[550][550], b[550][550];char z;queue<int> q;
void A(int u, int v, int w) {e[++c] = {v, w, h[u]};h[u] = c;}
bool B()
{
    memset(d, 0, sizeof d);d[s] = 1;q.push(s);while(!q.empty())
    {
        int u = q.front();q.pop();g[u] = h[u];for(int i = h[u], v;i;i =
        e[i].t) if(e[i].w && !d[v = e[i].v]) d[v] = d[u] + 1, q.push(v);
    }
    return d[t];
}
int D(int u, int f)
{
    if(u == t) return f;
    int k, q = 0;
    for(int i = g[u], v;i && f;i = e[i].t)
    {
        g[u] = i;
        if(e[i].w && d[v = e[i].v] == d[u] + 1)
            k = D(v, min(e[i].w, f)), e[i].w -= k, e[i ^ 1].w += k, q += k, f -= k;
    }
    return q;
}
int main()
{
    scanf("%d%d", &n, &m);t = n + m;
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= m;++j)
            scanf(" %c", &z), a[i][j] = z == 'B';
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= m;++j)
            b[i][j] = a[i][j] ^ a[i + 1][j] ^ a[i][j + 1] ^ a[i + 1][j + 1];
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= m;++j)
            r += b[i][j];
    for(int i = 1;i < n;++i)
        for(int j = 1;j < m;++j)
            if(b[i][j] && b[i][m] && b[n][j])
                A(i, j + n, 1), A(j + n, i, 0);
    for(int i = 1;i < n;++i) A(0, i, 1), A(i, 0, 0);
    for(int i = 1;i < m;++i) A(i + n, t, 1), A(t, i + n, 0);
    while(B()) p += D(0, 1e9);r -= p;
    r -= b[n][m] && p & 1;
    r += !b[n][m] && p & 1;
    return !printf("%d", r);
}
posted @ 2023-07-03 10:29  Jijidawang  阅读(6)  评论(0)    收藏  举报  来源