You are given three n × n matrices AB and C. Does the equation A × B = C hold true?

Input

The first line of input contains a positive integer n (n ≤ 500) followed by the the three matrices AB and respectively. Each matrix's description is a block of n × n integers.

It guarantees that the elements of A and B are less than 100 in absolute value and elements of C are less than 10,000,000 in absolute value.

Output

Output "YES" if the equation holds true, otherwise "NO".

Sample Input

2
1 0
2 3
5 1
0 8
5 1
10 26

Sample Output

YES

Hint

Multiple inputs will be tested. So O(n 3) algorithm will get TLE.

 

 

 

 

题解

题目中有明显的提示,不能直接用矩阵乘法

我们应该考虑一个时间复杂度更低的算法

我们很容易想到随机A的一行与B的一列,乘起来,计算一下乘积

但是这样的随机化的正确率很低

当数据中只有一个位置不正确时,随机T次的正确率为1-(1-\frac{1}{n^2})^T,在n=500的情况下大概随机575645次正确率才为90%

比暴力还差。。。

我们考虑一下直接验证一行,这样随机T次的正确率为1-(1-\frac{1}{n})^T,只要大概1150次检验,但是检验复杂度为n^2了

还是比暴力慢。。。

我们应该怎么办呢?

发现上面两种方法的本质都是一样的,只算一部分来进行检验

考虑有没有方法可以一次性检验所有的数且时间复杂度较低

我们可以把B矩阵每个点乘一个权值,再按行进行加和,得到 B' ,做A与 B' 的矩阵乘法

通过暴力计算可以算出得到的积矩阵与C矩阵的关系

即:对C进行与B相同的操作(乘权值,加和)之后,得到的矩阵C'与A*B'相等

这样我们就可以完成O(n^2)全部数的检验了

我们可以多做几次这样的检验(其实一次检验的正确率已经很高了)

代码:(为了方便,我只按列对B矩阵进行了赋权操作)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 505
#define LL long long
LL a[N][N],b[N][N],c[N][N],s[N],t[N],seed[N];
int main()
{
	srand(3993991);
	int n,i,j,tim;bool flg;
	while(~scanf("%d",&n)){
		memset(s,0,sizeof(s));memset(t,0,sizeof(t));flg=0;
		for(i=1;i<=n;i++)for(j=1;j<=n;j++)scanf("%lld",&a[i][j]);
		for(i=1;i<=n;i++)for(j=1;j<=n;j++)scanf("%lld",&b[i][j]);
		for(i=1;i<=n;i++)for(j=1;j<=n;j++)scanf("%lld",&c[i][j]);
		for(tim=1;tim<=10;tim++){
			for(i=1;i<=n;i++)seed[i]=rand()%n+1;
			memset(s,0,sizeof(s));memset(t,0,sizeof(t));
			for(i=1;i<=n;i++)for(j=1;j<=n;j++)t[i]+=1ll*b[i][j]*seed[j];
			for(i=1;i<=n;i++)for(j=1;j<=n;j++)s[i]+=1ll*a[i][j]*t[j];
			for(i=1;i<=n;i++){
				LL sum=0;for(j=1;j<=n;j++)sum+=1ll*c[i][j]*seed[j];
				if(sum!=s[i]){flg=1;break;}
			}
			if(flg)break;
		}
		if(flg)printf("NO\n");
		else printf("YES\n");
	}
}