CF1592F2-Alice and Recoloring 2-分析、二分图

link:https://codeforces.com/contest/1592/problem/F2
题意:给定一个 \(n\)\(m\) 列的目标矩阵,矩阵元素只有 W 或 B ,并且你有一个初始矩阵,元素全为 W 。
现在你可以矩阵实施以下操作:

  • 使用一块钱,选定一个包含 \((1,1)\) 的子矩阵,把矩阵中的元素全部反转( W 变 B , B 变 W )。
  • 使用三块钱,选定一个包含 \((n,1)\) 的子矩阵,把矩阵中的元素全部反转。
  • 使用四块钱,选定一个包含 \((1,m)\) 的子矩阵,把矩阵中的元素全部反转。
  • 使用两块钱,选定一个包含 \((n,m)\) 的子矩阵,把矩阵中的元素全部反转。
    现在需要你求出把初始矩阵变为目标矩阵最少需要几块钱。

\(1\leq n,m\leq 500\).


首先四个操作中有一些直接是没有用的:

  • 右上角花费4元的操作,可以用2次左上角1元解决
  • 左下角花费3元的操作,也可以用2次左上角1元解决
  • 那么只剩下左上和右下角的
    操作相当于区间(二维的)异或,考虑做一个差分数组 \(s_{i,j}=a_{i,j}\oplus a_{i,j+1}\oplus a_{i_+1,j}\oplus a_{i+1,j+1}\)(网格外的一律当做单位元 \(0\)),那么操作1相当于单点修改 \(s_{i,j}\),右下角相当于修改四个位置 \(s_{i-1,j-1},s_{n,j-1},s_{i-1,m},s_{n,m}\)

那么就变成:

  • 花费1块钱做单点修改
  • 花费2块钱可以修改4个特定的位置
    对于这 \(4\) 个位置注意到:
  • (1)一行至多被操作一次,否则 \(s_{n,m},s_{i-1,m}\) 相当于不变,每次只修改 \(2\) 个位置,可以直接用操作1代替
  • (2)一个位置如果要修改,必须 \(s_{i-1,j-1},s_{i-1,m},s_{n,j-1}\) 都是 \(1\) ,否则如果有一个不是 \(1\),操作完了还要花钱把它改回来,花费了 \(2+1=3\) 块钱,用操作1也是同样的花费

因此对于所有满足 \(s_{i-1,j-1},s_{n,j-1},s_{i-1,m}\) 都是 \(1\) 的位置 \((i,j)\) 连一条左边 \(i\) 到右边 \(j\) 的边(网格图每行每列经典的二分图),相当于每行每列至多选一次,并且只有满足条件的可能被选上。

正常用操作1花费是所有\(s_{i,j}=1\) 的个数,对于操作 \(2\) 先不考虑最右下角的点,那么相当于用2块钱改了3个点,少一块钱,因此答案=\(s-\)二分图的最大匹配。
最后考察右下角:看最大流的奇偶性,如果同奇偶性就不用额外花费,否则答案+1

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
using namespace std;

template<class T>
struct Dinic{//ind from 0 to n-1
    struct Edge{
        int to;T cap;
        Edge(int to,T cap):to(to),cap(cap){}
    };
    int n;
    vector<Edge> E;
    vector<vector<int>> G;
    vector<int> cur,h;

    Dinic(int n=0){init(n);}
    void init(int n){
        this->n=n;
        E.clear();
        cur.resize(n);
        h.resize(n);
        G.assign(n,{});
    }
    void addEdge(int u,int v,T c){
        G[u].push_back(E.size());E.emplace_back(v,c);
        G[v].push_back(E.size());E.emplace_back(u,0);
    }
    bool bfs(int s,int t){
        h.assign(n,-1);
        queue<int> que;
        h[s]=0;
        que.push(s);
        while(!que.empty()){
            const int u=que.front();
            que.pop();
            for(auto i:G[u]){
                auto [v,c]=E[i];
                if(c>0&&h[v]==-1){
                    h[v]=h[u]+1;
                    if(v==t)return true;
                    que.push(v);
                }
            }
        }
        return false;
    }
    T dfs(int u,int t,T f){
        if(u==t)return f;
        auto r=f;
        for(int &i=cur[u];i<(int)G[u].size();i++){
            const int j=G[u][i];
            auto [v,c]=E[j];
            if(c>0&&h[v]==h[u]+1){
                auto a=dfs(v,t,std::min(r,c));
                E[j].cap-=a;
                E[j^1].cap+=a;
                r-=a;
                if(r==0)return f;
            }
        }
        return f-r;
    }
    T work(int s,int t){
        T ans=0;
        while(bfs(s,t)){
            cur.assign(n,0);
            ans+=dfs(s,t,std::numeric_limits<T>::max());
        }
        return ans;
    }
    vector<bool> minCut(){
        vector<bool> c(n);
        rep(i,0,n-1)c[i]=(h[i]!=-1);
        return c;
    }
    struct scheme{
        int u,v;
        T cap,flow;
    };
    vector<scheme> get(){
        vector<scheme> ans;
        for(int i=0;i<(int)E.size();i+=2)
            ans.push_back({E[i+1].to,E[i].to,E[i].cap+E[i+1].cap,E[i+1].cap});
        return ans;
    }
};
int main(){
    fastio;
    int n,m;
    cin>>n>>m;
    auto a=vector<vector<int>>(n+2,vector<int>(m+2));
    auto s=vector<vector<int>>(n+2,vector<int>(m+2));
    rep(i,1,n){
        string s;
        cin>>s;
        rep(j,1,m)a[i][j]=(s[j-1]=='B');
    }
    rep(i,1,n)rep(j,1,m)s[i][j]=(a[i][j]^a[i+1][j]^a[i][j+1]^a[i+1][j+1]);
    
    //[1,n],[n+1,n+m]
    int S=n+m+1,T=n+m+2;
    Dinic<int> flow(T+1);
    int ans=0;
    rep(i,1,n)rep(j,1,m)ans+=s[i][j];
    rep(i,1,n-1)rep(j,1,m-1)if(s[i][j]&&s[n][j]&&s[i][m])flow.addEdge(i,j+n,1);
    rep(i,1,n)flow.addEdge(S,i,1);
    rep(j,1,m)flow.addEdge(j+n,T,1);
    int f=flow.work(S,T);
    ans-=s[n][m];
    ans=ans-f+((f&1)^s[n][m]);
    cout<<ans;
    return 0;
}
posted @ 2024-09-26 22:19  yoshinow2001  阅读(5)  评论(0编辑  收藏  举报