ICPC济南A-Matrix Equation:高斯消元,异或线性方程

题目大意:

给你两个大小为 n n n的 01 01 01方阵 A , B A,B A,B.问你有多少个方阵 C C C满足 A ∗ C = B & C A*C=B\&C A∗C=B&C. ∗ 代 表 模 2 意 义 下 的 矩 阵 乘 法 , & 代 表 两 个 矩 阵 的 每 个 位 置 相 与 *代表模2意义下的矩阵乘法,\&代表两个矩阵的每个位置相与 ∗代表模2意义下的矩阵乘法,&代表两个矩阵的每个位置相与

n ≤ 200 n \leq 200 n≤200

题目思路:

不难对结果矩阵的每个位置 ( i , j ) (i,j) (i,j)列一个等式:

∑ i = 1 k A i , k C k , j    ( m o d   2 ) = B i , j C i , j \sum_{i=1}^{k}A_{i,k}C_{k,j} \ \ (mod \ 2)=B_{i,j}C_{i,j} ∑i=1k​Ai,k​Ck,j​  (mod 2)=Bi,j​Ci,j​

我们知道模二意义下的加法等于异或,那么推出:
⊕ i = 1 k A i , k C k , j = B i , j C i , j \oplus_{i=1}^{k} A_{i,k}C_{k,j}=B_{i,j}C_{i,j} ⊕i=1k​Ai,k​Ck,j​=Bi,j​Ci,j​
进一步推出:
B i , j C i , j ⊕ i = 1 k A i , k C k , j = 0 B_{i,j}C_{i,j}\oplus_{i=1}^{k} A_{i,k}C_{k,j}=0 Bi,j​Ci,j​⊕i=1k​Ai,k​Ck,j​=0

将 C i , j C_{i,j} Ci,j​的系数合并得到:

A i , 1 C 1 , j ⊕ . . . ⊕ [ A i , i = = B i , j ] C i , j ⊕ . . . ⊕ A i , n C n , j = 0    − 式 ① A_{i,1}C_{1,j}\oplus ...\oplus [A_{i,i}==B_{i,j}]C_{i,j}\oplus ...\oplus A_{i,n}C_{n,j}=0\ \ -式① Ai,1​C1,j​⊕...⊕[Ai,i​==Bi,j​]Ci,j​⊕...⊕Ai,n​Cn,j​=0  −式①

至此,我们有 n 2 n^2 n2个方程, n 2 n^2 n2个未知数,所以显然有 O ( n 6 64 ) O(\frac{n^6}{64}) O(64n6​)的高斯消元的做法,不可行.考虑进一步优化.

观察式子①:我们发现矩阵 C C C是列独立的。也就是说:对 C i , j C_{i,j} Ci,j​列出的方程只会涉及到第 j j j列中的未知数 C r , j , r ∈ [ 1 , n ] C_{r,j},r \in[1,n] Cr,j​,r∈[1,n]。不同列之间的元素没有共同的方程。那么我们可以按列计算,每一列的答案根据乘法原理相乘即可得到最终答案.

复杂度降到: O ( n 4 64 ) O(\frac{n^4}{64}) O(64n4​). 可做.

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200 + 5;
const int mod = 998244353;
int f[maxn][maxn] , g[maxn][maxn];
ll ksm (ll a , ll b){ ll ans = 1 , base = a;
while (b){if (b & 1) ans = ans * base % mod;b >>= 1;base = base * base % mod;}return ans;}
bitset<maxn> a[maxn];
int n;
ll guess (int x)
{
    // 计算系数
    for (int i = 1 ; i <= n ; i++){
        for (int j = 1 ; j <= n ; j++){
            a[i][j] = f[i][j];
        }
        a[i][i] = (f[i][i] != g[i][x]);
    }
    // 跑高斯消元
    int r , c , free = 0;
    for (r = c = 1 ; r <= n && c <= n ; r++ , c++){
        int p = 0;
        for (int j = r ; j <= n ; j++){
            if (a[j][c]){
                p = j;
                break;
            }
        }
        if (!p){
            r--;
            free++;
            continue;
        }
        swap(a[r] , a[p]);
        for (int j = 1 ; j <= n ; j++){
            if (j == r) continue;
            if (a[j][c] == 0) continue;
            a[j] ^= a[r];
        }
    }
    return ksm(2 , free);
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1 ; i <= n ; i++)
        for (int j = 1 ; j <= n ; j++)
            cin >> f[i][j];
    for (int i = 1 ; i <= n ; i++)
        for (int j = 1 ; j <= n ; j++)
            cin >> g[i][j];
    ll ans = 1;
    for (int i = 1 ; i <= n ; i++) ans = (ans * guess(i))%mod;
    cout << ans << endl;
    return 0;
}
上一篇:BZOJ-3517 翻硬币(异或方程组)


下一篇:题解 P7096 【[yLOI2020] 泸沽寻梦】