题目

题目大意

给出三个行数和列数均为 \(n\) 的矩阵 \(A,B,C\),判断 \(AB=C\) 是否成立。

数据范围与提示

\(n\le 1000\),矩阵中的数字大于等于 \(0\) 小于 \(1000\),数据组数不超过 \(5\) 组。

解法

随机一个 \(n\times 1\) 的列向量 \(x\),我们 \(\mathcal O(n^2)\) 地判断 \(ABx\) 是否与 \(Cx\) 相等。关于 \(ABx\) 可以运用乘法结合律先算出 \(D=Bx\),再算出 \(ABx=AD\)

为啥捏?尝试分析 \(P(AB\ne C\and ABx=Cx)\)

首先转化一下 \(ABx=Cx\),发现满足条件的 \(x\in \text{ker}(AB-C)\)

而我们有结论:\(\text{rank}(A)+\text{dim}(\text{ker}(A))=n\)。因为 \(AB\ne C\),所以 \(\text{rank}(AB-C)\ge 1\),从而推出 \(\text{dim}(\text{ker}(A))\le n-1\)

由此观之,用 \(\text{ker}(AB-C)\) 组成子空间的维度至少比 \(V\) 的维度少 \(1\)。我们感性理解,从二维拓展到三维会使空间整点个数乘 \(t\)(其中 \(t\) 为值域包含整数个数),对于这道题大约就是 \(1000\)。所以概率约为 \(\frac{1}{1000}\),为了保险可以多随机几次。

代码

#include <cstdio>

#define print(x,y) write(x),putchar(y) 

template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}

#include <ctime>
#include <cstdlib>
using namespace std;

const int maxn=1005;

int n,a[maxn][maxn],r[maxn];
int b[maxn][maxn],c[maxn][maxn];
int d[maxn];

int main() {
	srand(time(NULL)); 
	while(scanf("%d",&n)!=EOF) {
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
				a[i][j]=read(9);
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
				b[i][j]=read(9);
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
				c[i][j]=read(9);
		bool flag=0;
		for(int T=1;T<=10;++T) {
			for(int i=1;i<=n;++i)
				r[i]=rand(),d[i]=0;
			for(int i=1;i<=n;++i)
				for(int j=1;j<=n;++j)
					d[i]+=b[i][j]*r[j];
			for(int i=1;i<=n;++i) {
				int t1=0,t2=0;
				for(int j=1;j<=n;++j)
					t1+=a[i][j]*d[j],
					t2+=c[i][j]*r[j]; 
				if(t1^t2) {
					flag=1; break;
				}
			}
			if(flag) break;
		}		
		puts(flag?"No":"Yes");
	}
	return 0;
}
posted on 2021-07-20 16:35  Oxide  阅读(82)  评论(0编辑  收藏  举报