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;
}