BZOJ2396 神奇的矩阵 <随机化>

Problem

神奇的矩阵

Time Limit: 5Sec5 Sec
Memory Limit: 512MB512 MB

Description

给出三个行数和列数均为NN的矩阵AABBCC,判断A×B=CA\times B=C是否成立。

Input

题目可能包含若干组数据。
对于每组数据,第一行一个数NN,接下来给出三个N×NN\times N的矩阵,依次为AABBCC三个矩阵。

Output

对于每组数据,若A×B=CA\times B=C成立,则输出YesYes,否则NoNo。每个答案占一行。

Sample Input

1
2
3
4
1
2
2
100

Sample Output

1
No

HINT

对于90%90\%的数据,NN不超过100100
对于100%100\%的数据,NN不超过10001000,矩阵中的数字大于等于00小于10001000,数据组数不超过55组。

标签:矩阵乘法 随机化

Solution

挺巧妙的一道随机化题。
首先考虑直接乘,由于N1000N\le 1000,而矩乘是O(n3)O(n^3),肯定会TLETLE
我们发现矩阵太大了,那么我们就要压缩矩阵,把这样一个正方形的矩阵压缩为一个行矩阵或列矩阵。
我们先随机出一个1×n1\times n的列矩阵RR,这样A×B×R=A×(B×R)A\times B\times R=A\times (B\times R),将结果与C×RC\times R比较。这样乘法的复杂度就降为O(n2)O(n^2),比较复杂度为O(n)O(n),总复杂度为O(n2)O(n^2)。如果觉得随机一次不保险,还可以多随机几次,不过只随一次也很容易过。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <bits/stdc++.h>
#define MAX_N 1000
#define MOD 1000000007
using namespace std;
int n;
struct Matrix {
int r, c; long long ele[MAX_N][MAX_N];
inline Matrix operator * (const Matrix &x) const {
Matrix ret; memset(ret.ele, 0, sizeof(ret.ele));
for (int i = 0; i < (ret.r = r); i++)
for (int j = 0; j < (ret.c = x.c); j++)
for (int k = 0; k < c; k++)
ret.ele[i][j] = (ret.ele[i][j]+ele[i][k]*x.ele[k][j])%MOD;
return ret;
}
} A, B, C, R;
int main() {
while (scanf("%d", &n)) {
A.r = A.c = n; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) scanf("%lld", &A.ele[i][j]);
B.r = B.c = n; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) scanf("%lld", &B.ele[i][j]);
C.r = C.c = n; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) scanf("%lld", &C.ele[i][j]);
srand(19260817); R.r = n, R.c = 1; for (int i = 0; i < n; i++) R.ele[i][0] = rand()*rand()%MOD;
A = A*(B*R), C = C*R; bool flag = true; for (int i = 0; i < n; i++) flag &= (A.ele[i][0] == C.ele[i][0]);
puts(flag ? "Yes" : "No");
}
return 0;
}