cf1592F2. Alice and Recoloring 2
题解
左下角和右上角操作没有用,只剩右下角和左上角的操作。
这步很妙:设 $a_{i,j}=(ch_{i,j}=='B'),b_{i,j}=a_{i,j}\ \text{xor}\ a_{i+1,j}\ \text{xor}\ a_{i,j+1}\ \text{xor}\ a_{i+1,j+1}$ ,那么左上角操作相当于反转 $a_{i,j}$ ,右下角操作相当于反转 $a_{i,j},a_{i,m},a_{n,j},a_{n,m}$ 。
因此,如果对 $(x,y_1),(x,y_2)$ 都进行右下角操作是不优的。而且,如果 $a_{i,j},a_{i,m},a_{n,j}$ 不同时为 $1$ ,那么进行右下角操作也是不优的。
因此,我们设 $n-1$ 个点代表行, $m-1$ 个点代表列,然后如果 $a_{i,j},a_{i,m},a_{n,j}$ 同时为 $1$ 就连边,跑最大二分图匹配即可。
代码
#include <bits/stdc++.h> using namespace std; const int N=1e6+5; int n,m,t=1,hd[N],V[N],W[N],nx[N],ans,d[N],cur[N],S,T,a[505][505]; char ch[505][505]; void add(int u,int v,int w){ nx[++t]=hd[u];V[hd[u]=t]=v;W[t]=w; } void ins(int u,int v,int w){ add(u,v,w);add(v,u,0); } queue<int>q; bool bfs(){ for (int i=1;i<=T;i++) d[i]=-1; d[S]=0;q.push(S); for (;!q.empty();){ int u=q.front();q.pop(); for (int i=hd[u];i;i=nx[i]) if (W[i] && !~d[V[i]]) d[V[i]]=d[u]+1,q.push(V[i]); } return d[T]!=-1; } int dfs(int u,int w){ if (u==T) return w; int s=0,v; for (int &i=cur[u];i;i=nx[i]){ if (W[i] && d[V[i]]==d[u]+1 && (v=dfs(V[i],min(w,W[i])))) w-=v,W[i]-=v,W[i^1]+=v,s+=v; if (!w) break; } return s; } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%s",ch[i]+1); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) a[i][j]=(ch[i][j]=='B')^(ch[i][j+1]=='B')^(ch[i+1][j]=='B')^(ch[i+1][j+1]=='B'); for (int i=1;i<n;i++) for (int j=1;j<m;j++) if (a[i][j] && a[i][m] && a[n][j]) ins(i,j+n-1,1); S=n+m-1;T=S+1; for (int i=1;i<n;i++) ins(S,i,1); for (int i=1;i<m;i++) ins(i+n-1,T,1); while(bfs()){ for (int i=1;i<=T;i++) cur[i]=hd[i]; ans+=dfs(S,1e9); } a[n][m]^=(ans&1);ans=-ans; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) ans+=a[i][j]; printf("%d\n",ans); return 0; }