To_Heart—题解——CF1592F1

题目链接

Link.

题解

神仙题啊神仙题。

首先,这道题目的操作是反转,而反转两次就等价于没反转。所以从初始状态转换到目标状态等价于从目标状态转换到初始状态。

为了方便,这里把 ‘W’ 看成 0 0 0,把 ‘B’ 看成 1 1 1,每次反转就是将矩形 A A A 的每一个数异或 1 1 1。所求就是把所有数变成 0 0 0

可以发现,做一次操作 2 2 2 或操作 3 3 3 等价于做两次操作 1 1 1,以操作 2 2 2 为例,如果我想反转矩形 ( 1 , i ) (1,i) (1,i) ( 2 , m ) (2,m) (2,m),我可以先反转 ( 1 , 1 ) (1,1) (1,1) ( 2 , i − 1 ) (2,i-1) (2,i1),然后反转 ( 1 , 1 ) (1,1) (1,1) ( 2 , m ) (2,m) (2,m)。因为两次操作 1 1 1 的代价不高于一次操作 2 2 2 3 3 3,所以操作 2 2 2 3 3 3 是没有用的。

现在我们可以反转的矩形只有两种:

  1. ( 1 , 1 ) (1,1) (1,1) 为左上角
  2. ( n , m ) (n,m) (n,m) 为右下角

因为操作 1 1 1 的代价最小,所以我们先只考虑操作 1 1 1

对于一个点,我们怎么考虑它是否需要反转呢?

如果它自己是 1 1 1,那么它是需要反转的,但是如果它左边、下边、左下的点有 1 1 1 个或是 3 3 3 个需要反转,那么它自己就不用反转了,因为其它三个点一次或三次的反转一定都包含了这个点,那么这个点自然就被反转了。否则这个点一定要消耗 1 1 1 的代价反转。

同理也可以推出这个点是 0 的情况下是否需要反转。

总结一下,对于一个点,如果它与它左边、下边、左下的点异或的值为 1 1 1,那么这个点需要反转,为 0 0 0 就不需要反转。

定义一个新的矩形 B B B B , j = A i , j ⊕ A i + 1 , j ⊕ A i , j + 1 ⊕ A i + 1 , j + 1 B_{,j}=A_{i,j} \oplus A_{i+1,j} \oplus A_{i,j+1} \oplus A_{i+1,j+1} B,j=Ai,jAi+1,jAi,j+1Ai+1,j+1 ,操作 1 1 1 就相当于反转 B i , j B_{i,j} Bi,j

那么答案就是 a n s = ∑ i = 1 n ∑ j = 1 m B i , j ans=\sum_{i=1}^{n}\sum_{j=1}^{m} B_{i,j} ans=i=1nj=1mBi,j

但是因为还有一个操作 4 4 4,考虑操作 4 4 4 的作用。可以发现操作 4 4 4 就是将 B i , j , B i , m , B n , j , B n , m B_{i,j},B_{i,m},B_{n,j},B_{n,m} Bi,j,Bi,m,Bn,j,Bn,m 同时反转。

看起来操作 4 4 4 比操作 1 1 1 更优,但是因为不停的反转 B n , m B_{n,m} Bn,m,所以只有进行第一次操作 4 4 4 的时候才会取得更小的代价,特判即可。

code

int n,m;
char s[505][505];
int a[505][505];
int ans=0;

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>(s[i]+1);
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=s[i][j]!='W';
	for(int i=1;i<=n;i++) for(int j=1;j<=m;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++) ans+=a[i][j];
	for(int i=1;i<n;i++) for(int j=1;j<m;j++) if(a[i][j]&&a[n][j]&&a[i][m]&&a[n][m]){ ans--;goto Thanks; }
	Thanks:;
	cout<<ans<<endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值