题目
题目大意
给出三个行数和列数均为 (n) 的矩阵 (A,B,C),判断 (AB=C) 是否成立。
数据范围与提示
(nle 1000),矩阵中的数字大于等于 (0) 小于 (1000),数据组数不超过 (5) 组。
解法
随机一个 (n imes 1) 的列向量 (x),我们 (mathcal O(n^2)) 地判断 (ABx) 是否与 (Cx) 相等。关于 (ABx) 可以运用乘法结合律先算出 (D=Bx),再算出 (ABx=AD)。
为啥捏?尝试分析 (P(AB e Cand ABx=Cx))。
首先转化一下 (ABx=Cx),发现满足条件的 (xin ext{ker}(AB-C))。
而我们有结论:( ext{rank}(A)+ ext{dim}( ext{ker}(A))=n)。因为 (AB e C),所以 ( ext{rank}(AB-C)ge 1),从而推出 ( ext{dim}( ext{ker}(A))le n-1)。
由此观之,用 ( ext{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;
}