第45届ICPC济南站A题 Matrix Equation(高斯消元)
题意
给两个 \(n\times n\) 的 \(01\) 矩阵 \(A,B\),问有多少种 \(01\) 矩阵 \(C\) 满足 \(A\times C=B\cdot C\)。
题解
把 \(A\times C=B\cdot C\) 打开,得:
\[A_{1,1}\cdot C_{1,1}+A_{1,2}\cdot C_{2,1}+...+A_{1,n}\cdot C_{n,1}=B_{1,1}\cdot C_{1,1} \\
A_{1,1}\cdot C_{1,2}+A_{1,2}\cdot C_{2,2}+...+A_{1,n}\cdot C_{n,2}=B_{1,2}\cdot C_{1,2} \\
... \\
A_{n,1}\cdot C_{1,n}+A_{n,2}\cdot C_{2,n}+...+A_{n,n}\cdot C_{n,n}=B_{n,n}\cdot C_{n,n} \\
\]
按理来说找到这个 \(n^2\) 的线性方程组中自由元的个数 \(x\) 就能得出答案 \(2^x\) 了,但是复杂度不允许。再观察可以发现,对于每一列的未知数 \(C_{1,i},C_{2,i},...,C_{n,i}\) 可以形成一组独立的线性方程组,与其他列互不干扰:
\[A_{1,1}\cdot C_{1,i}+A_{1,2}\cdot C_{2,i}+...+A_{1,n}\cdot C_{n,i}=B_{1,i}\cdot C_{1,i} \\
A_{2,1}\cdot C_{1,i}+A_{2,2}\cdot C_{2,i}+...+A_{2,n}\cdot C_{n,i}=B_{2,i}\cdot C_{2,i} \\
... \\
A_{n,1}\cdot C_{1,i}+A_{n,2}\cdot C_{2,i}+...+A_{n,n}\cdot C_{n,i}=B_{n,i}\cdot C_{n,i} \\
\]
那么可以对于每一列列出系数矩阵,求自由元个数 \(x_i\),最终答案即为 \(2^{x_1+x_2+...+x_n}\)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=210;
const int mod=998244353;
int n,a[N][N],b[N][N];
bitset<N> m[N];
LL qpow(LL x,LL k){
LL res=1;
while(k){
if(k&1) res=res*x%mod;
x=x*x%mod;
k>>=1;
}
return res;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&b[i][j]);
LL ans=1;
for(int w=1;w<=n;w++){
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) m[i][j]=a[i][j];
for(int i=1;i<=n;i++) m[i][i]=m[i][i]^b[i][w];
for(int i=1,pos=1;pos<=n;i++){
while(pos<=n) {
for(int j=i+1;j<=n;j++) if(m[j][pos]) swap(m[j],m[i]);
if(m[i][pos]) break;
pos++;
}
if(pos>n) {ans=ans*qpow(2,n-i+1)%mod;break;}
for(int j=i+1;j<=n;j++)
if(m[j][pos]) m[j]^=m[i];
}
}
printf("%lld\n",ans);
return 0;
}