2020 ICPC 济南站 A - Matrix Equation // 高斯消元

题目来源:第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南)A

题目链接:A-Matrix Equation


题意

定义01矩阵的两种运算:对于大小为 \(N \times N\) 的01矩阵 \(X\)\(Y\),记 \(Z = X \times Y\)\(D = X \odot Y\),则有 \(Z_{i,j} = (\sum_{k=1}^{N}X_{i,k}Y_{k,j})\ mod\ 2\)\(D_{i,j} = X_{i,j}Y_{i,j}\).

对于给定的两个 \(N \times N\) 的01矩阵 \(A\)\(B\),求有多少个 \(N \times N\) 的01矩阵 \(C\),满足 \(A \times C = B \odot C\),答案对 \(998244353\) 取模。

数据范围:\(1 \le N \le 200\)\(A_{i,j},B_{i,j} \in \{0,1\}\).

思路:高斯消元 + bitset优化

根据条件限制,可以得到 \(N \times N\) 个 含有 \(N \times N\) 个未知量的方程,未知量就是矩阵 \(C\) 的所有元素。

对方程组进行求解,每一个未知量要么是确定的值,要么是自由未知量,取值任意(可以任取 \(0/1\))。因此,若记自由未知量的个数为 \(cnt\),答案就是 \(\large 2^{cnt}\).

但是直接进行高斯消元的话,复杂度是 \(O(n^6)\),是无法接受的,需要进行优化。

观察限制条件的左右式子,可以发现,\(C\) 的不同列是相互独立的,因此可以考虑对 \(C\) 的每一列进行高斯消元,复杂度为 \(O(n·n^3)\) ,即\(O(n^4)\).

又因为矩阵元素的值只有 \(0\)\(1\),因此可以用bitset进行优化,复杂度降为 \(O(n·{\large \frac{n^3}{\omega}})\),即 \(O({\large \frac{n^4}{\omega}})\),其中 \(\omega = 32\ or\ 64\),与机器有关。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;

const int N = 210;
const int mod = 998244353;

int n, A[N][N], B[N][N];
bitset<N> b[N];

int gauss()
{
    int c, r;
    for(c = 1, r = 1; c <= n; ++ c) {
        int t = r;
        for(int i = r; i <= n && !b[t][c]; ++ i) t = i;
        if(!b[t][c]) continue;
        swap(b[r], b[t]);
        for(int i = r + 1; i <= n; ++ i) {
            if(b[i][c]) b[i] ^= b[r];
        }
        ++ r;
    }
    return n + 1 - r;
}

int qmi(int m, int k, int p)
{
    int res = 1;
    while(k) {
        if(k & 1) res = (LL)res * m % p;
        m = (LL)m * m % p;
        k >>= 1;
    }
    return res;
}

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    cin >> n;
    for(int i = 1; i <= n; ++ i) {
        for(int j = 1; j <= n; ++ j) cin >> A[i][j];
    }
    for(int i = 1; i <= n; ++ i) {
        for(int j = 1; j <= n; ++ j) cin >> B[i][j];
    }

    int cnt = 0;
    for(int j = 1; j <= n; ++ j) {
        for(int i = 1; i <= n; ++ i) b[i].reset();
        for(int i = 1; i <= n; ++ i) {
            for(int k = 1; k <= n; ++ k) b[i][k] = A[i][k];
            b[i][i] = b[i][i] ^ B[i][j];
        }
        cnt += gauss();
    }

    cout << qmi(2, cnt, mod) << endl;

    return 0;
}
posted @ 2022-11-07 23:47  Jakon  阅读(157)  评论(0)    收藏  举报