题目
题目大意
给出三个行数和列数均为 \(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;
}