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

2023大厂真题提交网址(含题解):

www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
在这里插入图片描述

题目大意:

给你两个大小为 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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值