思路还是挺奇特的,真是一道值得纪念的题呢
题意简述
给你两个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;
}