Bootstrap

CF1983B 题解

思路还是挺奇特的,真是一道值得纪念的题呢

题意简述

给你两个n*m的矩阵,每个元素是0,1,2中的一个,问A矩阵是否能通过若干次操作得到B矩阵。

操作:选取一个子矩阵,长度和宽度均大于等于2,将四个顶点上的数加上如下图所示的矩阵并对3取模。

思路

观察特征

一个操作做完之后,每一行,每一列的和mod3其实并没有变化,因为每行每列都加上了3,mod3为0。

利用特征构造解法

每一次我们都选择一个2*2的矩阵进行操作。i从1开始枚举到n-1,j从1开始枚举到m-1,每次以(i,j)为左上角执行操作,使(i,j)上的值与B矩阵中(i,j)上的值相同。这样做每次都只会影响到后面的点,不会影响到已经改好的前面的点。操作完之后A矩阵左上角(n-1)*(n-1)的子矩阵已经与B矩阵相同,只剩下最后一行与最后一列。由于操作后每行每列的和mod3依然与原矩阵相同,可以直接通过和确定每行每列最后剩下的那一个,如果与B矩阵相同,那么就成功了,反之则不成功。

程序简化

由于按照上述步骤操作一定可以得到答案,所以其实不用模拟。算出A,B矩阵每行每列的和mod3的值,由于A矩阵在操作中不会改变和mod3的值,所以可以直接判断A与B每行每列的和mod3是否都相同,如果不相同,在左上角(n-1)*(n-1)的矩阵变成B之后剩下的一个肯定与B不同,不成功,如果相同,则成功。

代码

#include<bits/stdc++.h>
using namespace std;
int t,n,m,a[505][505],b[505][505],sumr[2][505],sumc[2][505];
char s[505];
int main(){
	scanf("%d",&t);
	while(t--){
		memset(sumr,0,sizeof(sumr));
		memset(sumc,0,sizeof(sumc));
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++){
			scanf("%s",s);
			for(int j=1;j<=m;j++){
				a[i][j]=s[j-1];
				sumr[0][i]+=a[i][j];
				sumc[0][j]+=a[i][j];
			}
		}	
		for(int i=1;i<=n;i++){
			scanf("%s",s);
			for(int j=1;j<=m;j++){
				b[i][j]=s[j-1];
				sumr[1][i]+=b[i][j];
				sumc[1][j]+=b[i][j];
			}
		}
		bool flag=1;
		for(int i=1;i<=n;i++) 
			if(sumr[0][i]%3!=sumr[1][i]%3){
				flag=0;
				break;
			}
		if(!flag){
			printf("No\n");
			continue;
		}
		for(int i=1;i<=m;i++) 
			if(sumc[0][i]%3!=sumc[1][i]%3){
				flag=0;
				break;
			}
		if(!flag) printf("No\n");
		else printf("Yes\n");
	}
	return 0;
}

;