传送门: https://ac.nowcoder.com/acm/contest/10662/A
题意
设 A × C = B ⋅ C , A×C=B⋅C, A×C=B⋅C,求C的个数。
思路
比赛的时候猜答案是2的幂次,确实没错,然后想解法是先求A的逆,最后答案为 C = A − 1 × B ⋅ C C=A^{-1}×B⋅C C=A−1×B⋅C,那么就意味着, A − 1 × B A^{-1}×B A−1×B这个结果,如果为0,那么可以去0或1,如果是1,那么只能取1,所以答案为 2 0 的 个 数 2^{0的个数} 20的个数,可是,A可能没有逆,所以这个方法是行不通的。
先来观察式子:
[
A
11
A
12
⋯
A
1
n
A
21
A
22
⋯
A
2
n
⋮
⋮
⋱
⋮
A
n
1
A
n
2
⋯
A
n
n
]
×
[
C
11
C
12
⋯
C
1
n
C
21
C
22
⋯
C
2
n
⋮
⋮
⋱
⋮
C
n
1
C
n
2
⋯
C
n
n
]
=
[
B
11
∗
C
11
B
12
∗
C
12
⋯
B
1
n
∗
C
1
n
B
21
∗
C
21
B
22
∗
C
22
⋯
B
2
n
∗
C
2
n
⋮
⋮
⋱
⋮
B
n
1
∗
C
n
1
B
n
2
∗
C
n
2
⋯
B
n
n
∗
C
n
n
]
\begin{bmatrix} A_{11}& A_{12}& \cdots & A_{1n}\\ A_{21}& A_{22}& \cdots & A_{2n}\\ \vdots & \vdots & \ddots & \vdots \\ A_{n1}& A_{n2}& \cdots &A_{nn} \end{bmatrix}× \begin{bmatrix} C_{11}& C_{12}& \cdots & C_{1n}\\ C_{21}& C_{22}& \cdots & C_{2n}\\ \vdots & \vdots & \ddots & \vdots \\ C_{n1}& C_{n2}& \cdots &C_{nn} \end{bmatrix}=\begin{bmatrix} B_{11}*C_{11}& B_{12}*C_{12}& \cdots & B_{1n}*C_{1n}\\ B_{21}*C_{21}& B_{22}*C_{22}& \cdots & B_{2n}*C_{2n}\\ \vdots & \vdots & \ddots & \vdots \\ B_{n1}*C_{n1}& B_{n2}*C_{n2}& \cdots &B_{nn}*C_{nn} \end{bmatrix}
⎣⎢⎢⎢⎡A11A21⋮An1A12A22⋮An2⋯⋯⋱⋯A1nA2n⋮Ann⎦⎥⎥⎥⎤×⎣⎢⎢⎢⎡C11C21⋮Cn1C12C22⋮Cn2⋯⋯⋱⋯C1nC2n⋮Cnn⎦⎥⎥⎥⎤=⎣⎢⎢⎢⎡B11∗C11B21∗C21⋮Bn1∗Cn1B12∗C12B22∗C22⋮Bn2∗Cn2⋯⋯⋱⋯B1n∗C1nB2n∗C2n⋮Bnn∗Cnn⎦⎥⎥⎥⎤
根
据
矩
阵
乘
法
可
以
知
道
C
矩
阵
第
一
列
的
方
程
组
为
:
根据矩阵乘法可以知道C矩阵第一列的方程组为:
根据矩阵乘法可以知道C矩阵第一列的方程组为:
[
A
11
∗
C
11
+
A
12
∗
C
21
+
.
.
.
+
A
1
n
∗
C
n
1
=
B
11
∗
C
11
⋮
A
21
∗
C
11
+
A
22
∗
C
21
+
.
.
.
+
A
2
n
∗
C
n
1
=
B
21
∗
C
21
⋮
A
n
1
∗
C
11
+
A
n
2
∗
C
21
+
.
.
.
+
A
n
n
∗
C
n
1
=
B
n
1
∗
C
n
1
]
\begin{bmatrix} A_{11}*C_{11}+A_{12}*C_{21}+...+A_{1n}*C_{n1}=B_{11}*C_{11}\\ \vdots\\ A_{21}*C_{11}+A_{22}*C_{21}+...+A_{2n}*C_{n1}=B_{21}*C_{21}\\ \vdots\\ A_{n1}*C_{11}+A_{n2}*C_{21}+...+A_{nn}*C_{n1}=B_{n1}*C_{n1} \end{bmatrix}
⎣⎢⎢⎢⎢⎢⎢⎡A11∗C11+A12∗C21+...+A1n∗Cn1=B11∗C11⋮A21∗C11+A22∗C21+...+A2n∗Cn1=B21∗C21⋮An1∗C11+An2∗C21+...+Ann∗Cn1=Bn1∗Cn1⎦⎥⎥⎥⎥⎥⎥⎤
[ ( A 11 − B 11 ) ∗ C 11 + A 12 ∗ C 21 + . . . + A 1 n ∗ C n 1 = 0 A 21 ∗ C 11 + ( A 22 − B 21 ) ∗ C 21 + . . . + A 2 n ∗ C n 1 = 0 ⋮ A n 1 ∗ C 11 + A n 2 ∗ C 21 + . . . + ( A n n − B n 1 ) ∗ C n 1 = 0 ] \begin{bmatrix} (A_{11}-B_{11})*C_{11}+A_{12}*C_{21}+...+A_{1n}*C_{n1}=0\\ A_{21}*C_{11}+(A_{22}-B_{21})*C_{21}+...+A_{2n}*C_{n1}=0\\ \vdots\\ A_{n1}*C_{11}+A_{n2}*C_{21}+...+(A_{nn}-B_{n1})*C_{n1}=0 \end{bmatrix} ⎣⎢⎢⎢⎡(A11−B11)∗C11+A12∗C21+...+A1n∗Cn1=0A21∗C11+(A22−B21)∗C21+...+A2n∗Cn1=0⋮An1∗C11+An2∗C21+...+(Ann−Bn1)∗Cn1=0⎦⎥⎥⎥⎤
所 以 每 列 都 是 相 互 独 立 的 , 所 以 我 们 求 每 列 的 种 数 , 最 后 全 部 乘 起 来 就 好 。 所以每列都是相互独立的,所以我们求每列的种数,最后全部乘起来就好。 所以每列都是相互独立的,所以我们求每列的种数,最后全部乘起来就好。
由 于 这 个 矩 阵 乘 法 有 一 个 要 求 , 最 后 求 得 的 要 相 加 并 % 2 , 这 是 什 么 ? 这 不 就 是 异 或 吗 ? 由于这个矩阵乘法有一个要求,最后求得的要相加并\%2,这是什么?这不就是异或吗? 由于这个矩阵乘法有一个要求,最后求得的要相加并%2,这是什么?这不就是异或吗?
那 么 答 案 是 多 少 ? 每 一 列 的 种 数 是 多 少 ? 答 案 就 是 上 面 每 一 个 异 或 方 程 组 的 自 由 元 的 个 数 n − r , r 为 方 程 组 的 秩 。 每 个 值 都 可 以 取 0 或 1 , 即 答 案 为 2 n − r 。 最 后 将 所 有 列 的 种 数 相 乘 即 可 。 那么答案是多少?每一列的种数是多少?答案就是上面每一个异或方程组的自由元的个数n-r,r为方程组的秩。每个值都可以取0或1,即答案为2^{n-r}。最后将所有列的种数相乘即可。 那么答案是多少?每一列的种数是多少?答案就是上面每一个异或方程组的自由元的个数n−r,r为方程组的秩。每个值都可以取0或1,即答案为2n−r。最后将所有列的种数相乘即可。
Code()
#include "bits/stdc++.h"
using namespace std;
#define FZT_ACM_LOCAL 1
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pdd;
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)
#define mem(a, b) memset(a , b , sizeof(a))
#define FOR(i, x, n) for(int i = x;i <= n; i++)
const ll mod = 998244353;
// const ll mod = 1e9 + 7;
// const double eps = 1e-6;
// const double PI = acos(-1);
// const double R = 0.57721566490153286060651209;
const int N = 210;
int a[N][N];//增广矩阵
int x[N];//解集
int freeX[N];//自由变元
// equ:方程个数 var:变量个数
int Gauss(int equ, int var) {//返回自由变元个数
/*初始化*/
for (int i = 0; i <= var; i++) {
x[i] = 0;
freeX[i] = 0;
}
/*转换为阶梯阵*/
int col = 0;//当前处理的列
int num = 0;//自由变元的序号
int k;//当前处理的行
for (k = 0; k < equ && col < var; k++, col++) {//枚举当前处理的行
int maxr = k;//当前列绝对值最大的行
for (int i = k + 1; i < equ; i++) {//寻找当前列绝对值最大的行
if (a[i][col] > a[maxr][col]) {
maxr = i;
swap(a[k], a[maxr]);//与第k行交换
break;
}
}
if (a[k][col] == 0) {//col列第k行以下全是0,处理当前行的下一列
freeX[num++] = col;//记录自由变元
k--;
continue;
}
for (int i = k + 1; i < equ; i++) {
if (a[i][col] != 0) {
for (int j = col; j < var + 1; j++) {//对于下面出现该列中有1的行,需要把1消掉
a[i][j] ^= a[k][j];
}
}
}
}
/*求解*/
//无解:化简的增广阵中存在(0,0,...,a)这样的行,且a!=0
for (int i = k; i < equ; i++)
if (a[i][col] != 0)
return -1;
//无穷解: 在var*(var+1)的增广阵中出现(0,0,...,0)这样的行
if (k < var)//返回自由变元数
return var - k;//自由变元有var-k个
//唯一解: 在var*(var+1)的增广阵中形成严格的上三角阵
for (int i = var - 1; i >= 0; i--) {//计算解集
x[i] = a[i][var];
for (int j = i + 1; j < var; j++)
x[i] ^= (a[i][j] && x[j]);
}
return 0;
}
ll quick_pow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans % mod;
}
int A[N][N];
int B[N][N];
void solve() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> A[i][j];
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> B[i][j];
}
}
ll ans = 0;
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
a[i][j] = A[i][j];
}
if (B[i][k]) a[i][i] ^= 1;
}
int cnt = Gauss(n, n);
ans += cnt > 0 ? cnt : 0;
}
cout << quick_pow(2, ans) << endl;
}
signed main() {
solve();
}