CF1592F Alice and Recoloring 题解

Codeforces F1
Codeforces F2
Luogu F1
Luogu F2

Description.

有一个 01 矩阵,现在你有以下四种操作

  1. 选择一个包括 \((1,1)\) 的矩阵并对其反色
  2. 选择一个包括 \((n,1)\) 的矩阵并对其反色
  3. 选择一个包括 \((1,m)\) 的矩阵并对其反色
  4. 选择一个包括 \((n,m)\) 的矩阵并对其反色

每个操作的权值是给定的,其中

1 代价 2 代价 3 代价 4 代价
F1 1 2 4 3
F2 1 3 4 2

问全都消成 \(0\) 的最小代价。

Solution.

首先,发现不管是 F1 还是 F2 23 操作根本没用。
因为 23 总是可以通过 \(2\)1 操作来完成。
肯定先贪心用 \(1\) 操作来覆盖。
这里相当于做个二阶差分。
考虑用 \(3\) 操作来替换 \(1\) 操作。
F1 的话就考虑如果有 \((n,m),(a,b),(a,m),(b,n)\) 就可以替换成 \(1\)\((a,b)_3\)
可以使答案减小当且仅当 \((n,m),(a,b),(a,m),(b,n)\) 都是 \(1\)
所以只需要替换一次。
F2 的话同理,\((n,m)\ne 1\) 时也可以替换使答案减小。
所以需要对其他都进行二分图匹配,先替换掉最多的 \(1\)
然后再判断 \((n,m)\) 即可。

Coding.

点击查看 F1 代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
int n,m;char ch[505][505],fg[505][505];
int main()
{
	read(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++) ch[i][j]=ch[i][j]=='B';
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) fg[i][j]=ch[i][j]^ch[i][j+1]^ch[i+1][j]^ch[i+1][j+1];
	int rs=0;for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) rs+=fg[i][j];
	if(fg[n][m]) for(int i=1;i<n;i++) for(int j=1;j<m;j++)
		if(fg[i][j]&&fg[i][m]&&fg[n][j]) return printf("%d\n",rs-1),0;
	return printf("%d\n",rs),0;
}
点击查看 F2 代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
int n,m,mt[505];char ch[505][505],fg[505][505],vs[505];
inline char dfs(int x)
{
	for(int y=1;y<m;y++) if(fg[x][y]&&fg[x][m]&&fg[n][y]&&!vs[y])
		{vs[y]=1;if(!mt[y]||dfs(mt[y])) return mt[y]=x,1;}
	return 0;
}
int main()
{
	read(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++) ch[i][j]=ch[i][j]=='B';
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) fg[i][j]=ch[i][j]^ch[i][j+1]^ch[i+1][j]^ch[i+1][j+1];
	int rs=0;for(int i=1;i<n;i++) memset(vs,0,sizeof(vs)),dfs(i);
	for(int j=1,i;j<m;j++) if(mt[j]) i=mt[j],fg[i][j]^=1,fg[i][m]^=1,fg[n][j]^=1,fg[n][m]^=1,rs+=2;
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) rs+=fg[i][j];
	int sm=rs-1;if(fg[n][m]) for(int i=1;i<n;i++) for(int j=1;j<m;j++)
		{int vl=sm-fg[i][j]-fg[i][m]-fg[n][j],tp=3-fg[i][j]-fg[i][m]-fg[n][j];rs=min(rs,tp+vl+2);}
	return printf("%d\n",rs),0;
}
posted @ 2021-10-05 08:03  Peal_Frog  阅读(66)  评论(0编辑  收藏  举报