A Matrix Equation
简要题意
定义矩阵的两种操作\(\times,*\),\((A \times B)_{i,j} = \sum_{k=1}^{n} A_{i,k}B_{k,j} \mod2\),\((A*B)_{i,j} = A_{i,j}B_{i,j}\),给定01矩阵\(A,B\),求有多少个01矩阵\(C\)满足\(A \times C = B * C\)。\(1 \leq n \leq 200\)
题解
首先这两种操作对列之间是独立的。这样的话可以对列分开考虑。
而\(*\)操作可以看成\(\times\)操作,也就是说\((B*C)_{i,j} = \sum_{k=1}^{n}B'_{i,k}C_{k,j}\)。\(B'_{i,j}=[i==j]B_{i,j}\)
令答案矩阵\(D = A \times C = B * C\),对\(D\)的每一列有
这样的话,令\(r\)等于\((A-B')\)的秩,每列答案的个数就是\(2^{n-r}\)次方。最后对所有答案求积就可以。注意要用bitset优化,复杂度\(O^{\frac{n^4}{64}}\)。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mn=205,mod=998244353;
int n;
ll ans=1;
bitset<mn> a[mn],b[mn],c[mn];
ll qpow(ll a,ll b) {
ll ans=1;
while(b) {
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int gauss()
{
int cnt=0;
for(int k=1,i=1;i<=n;++i) {
if(!c[k][i]) {
int flag=0;
for(int j=k+1;j<=n;++j) {
if(c[j][i]) {swap(c[j],c[k]);flag=1;break;}
}
if(!flag) {cnt++;continue;}
}
for(int j=k+1;j<=n;++j) if(c[j][i]) c[j]=c[j]^c[k];
k++;
}
return cnt;
}
int main()
{
scanf("%d",&n);
int tmp;
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) {scanf("%d",&tmp);a[i][j]=tmp;}
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) {scanf("%d",&tmp);b[i][j]=tmp;}
for(int t=1;t<=n;++t) {
for(int i=1;i<=n;++i) c[i]=a[i];
for(int i=1;i<=n;++i)
c[i][i]=c[i][i]^b[i][t];
ans=ans*qpow(2,gauss())%mod;
}
cout<<ans<<endl;
}