欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-12 14:10:56
...

题目大意:

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

n ≤ 200 n \leq 200 n200

题目思路:

不难对结果矩阵的每个位置 ( 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=1kAi,kCk,j  (mod 2)=Bi,jCi,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=1kAi,kCk,j=Bi,jCi,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,jCi,ji=1kAi,kCk,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,1C1,j...[Ai,i==Bi,j]Ci,j...Ai,nCn,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;
}
相关标签: 线性代数 算法