题目传送门 ( ̄︶ ̄)↗ 走你
题目大意:给你一个矩阵,你现在只能选取他其中的子方阵转置,次数不限,求是否能从矩阵A变换到矩阵B
构造变换方法,注意到转置偶数次与不转置时相同。
因为我们可以选择任意的子矩阵,所以我们可以构造如下的方法进行变换
-
选取一个子矩阵转置,并转置其一个子矩阵
这样变换之后,与原子矩阵只有第n行于n列不同,其余位置由于都转置了两次,所以位置不变
-
从子矩阵右下选取,使变换后的子矩阵于原矩阵只有右上和左下不同
因为原来第n行与第n列被转置一次,所以第一次转置时恢复原来的位置,但是除第n行与第n列外其余位置均转置了2次,所以再选择一个矩阵还原这些位置。
使用这样的变换方式,由于一直在交换左上和右下,不难看出对于一个元素aij,只能移动到位置anm,其中i+j=n+m,也就是沿着与副对角线平行的方向交换,所以我们只需要判断沿副对角线方向上的元素是否一致即可。
#include <stdio.h>
#include <climits>
#include <cstring>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <utility>
#include <vector>
#include <string>
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return
#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;
int N,M;
int A[512][512],B[512][512];
priority_queue<int> Q1;
priority_queue<int> Q2;
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
cin>>N>>M;
rep(i,1,N+1)
rep(j,1,M+1)
cin>>A[i][j];
rep(i,1,N+1)
rep(j,1,M+1)
cin>>B[i][j];
bool safe=true;
rep(i,1,M+1){
int posX=1,posY=i;
while(posX<=N && posY>0){
Q1.push(A[posX][posY]);
Q2.push(B[posX][posY]);
posX++,posY--;
}
int num1,num2;
while(!Q1.empty()){
num1=Q1.top();
num2=Q2.top();
Q1.pop(),Q2.pop();
if(num1!=num2){
safe=false;
break;
}
}
if(!safe)
break;
}
if(!safe){
cout<<"NO\n";
re 0;
}
rep(i,1,N+1){
int posX=i,posY=M;
while(posX<=N && posY>0){
Q1.push(A[posX][posY]);
Q2.push(B[posX][posY]);
posX++,posY--;
}
int num1,num2;
while(!Q1.empty()){
num1=Q1.top();
num2=Q2.top();
Q1.pop(),Q2.pop();
if(num1!=num2){
safe=false;
break;
}
}
if(!safe)
break;
}
if(safe)
cout<<"YES\n";
else
cout<<"NO\n";
re 0;
}