第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南)

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\)的每一列有

\[\vec{D_j}=A \times \vec{C_j} = B' \times \vec{C_j} \\ (A - B') \times \vec{C_j} = 0 \]

这样的话,令\(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;
}