2020 icpc济南 A - Matrix Equation (高斯消元求自由元个数)

链接:
A - Matrix Equation
题意:
给一个 A 矩阵 一个 B 矩阵(矩阵元素为 0 或 1),求有多少个 C 矩阵 满足 A X C = B . C (叉乘 和 点乘)。
思路:

  1. 赛中发现样例答案都是 2 的幂次 ,然后盲猜答案是二的幂次,队友暴力打了个表发现确实如此,然后随机造了一些样例发现答案好像是把某些 位置看成 一 块,然后就可以 把这一块全部取 0 或 1.然后慢慢的又发现 每一列可以单独考虑求有几个块 。(由于线代只实在学得菜 + 不知道高斯消元是什么 ,赛后才知道这就是所谓的自由元)。然后就开始自闭了,中间甚至连方程都推了,奈何实在是不知道高斯消元这个神奇的东西。然后就铜尾了(第 209 属实幸运)。。。
  2. 然后这题其实就是每一列单独考虑,然后列出方程组,稍微化简一下就是高斯消元求异或方程组自由元的题了在这里插入图片描述
    在这里插入图片描述
    就变成了上面的形式,就可以直接套模板了推荐一篇博客 高斯消元

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e2 + 7;
const int mod = 998244353;
int a[maxn][maxn];//增广矩阵
int x[maxn];//解集
int freeX[maxn];//自由变元
int n;
int A[maxn][maxn],B[maxn][maxn];
ll poww(ll a,ll b){
    
    
       ll ans=1;
       while(b > 0){
    
    
            if(b & 1) ans = ans * a % mod;
            a = a * a % mod;
            b >>= 1;

       }
       return ans;
}
int Gauss(int equ,int var){
    
    
    for(int i=0;i<=var;i++){
    
    
        x[i]=0;
        freeX[i]=0;
    }
    int col=0;//当前处理的列
    int num=0;//自由变元的序号
    int row;//当前处理的行
    for(row=0;row<equ&&col<var;row++,col++){
    
    //枚举当前处理的行
        int maxRow=row;//当前列绝对值最大的行
        for(int i=row+1;i<equ;i++){
    
    //寻找当前列绝对值最大的行
            if(abs(a[i][col])>abs(a[maxRow][col]))
                maxRow=i;
        }
        if(maxRow!=row){
    
    //与第row行交换
            for(int j=row;j<var+1;j++)
                swap(a[row][j],a[maxRow][j]);
        }
        if(a[row][col]==0){
    
    //col列第row行以下全是0,处理当前行的下一列
            freeX[num++]=col;//记录自由变元
            row--;
            continue;
        }
        for(int i=row+1;i<equ;i++){
    
    
            if(a[i][col]!=0){
    
    
                for(int j=col;j<var+1;j++){
    
    //对于下面出现该列中有1的行,需要把1消掉
                    a[i][j]^=a[row][j];
                }
            }
        }
    }
    for(int i=row;i<equ;i++)
        if(a[i][col]!=0)
            return -1;
    int temp=var-row;//自由变元有var-row个
    if(row<var)//返回自由变元数
        return temp;
    return 0;
}
void init() {
    
    
    for(int i = 0;i < n;i++) {
    
    
        for(int j = 0;j < n;j++) {
    
    
            a[i][j] = A[i][j];
        }
    }
}
int main(){
    
    
    scanf("%d",&n);
    for(int i = 0; i < n; i ++){
    
    
        for(int j = 0; j < n; j ++){
    
    
            scanf("%d",&A[i][j]);
            a[i][j] = A[i][j];
        }
    }
    for(int i = 0; i < n; i ++){
    
    
        for(int j = 0; j < n; j ++){
    
    
            scanf("%d",&B[i][j]);
        }
    }
    ll ans = 1;
    for(int r = 0;r < n; r ++){
    
    
        init();
        for(int i = 0; i < n; i ++){
    
    
            a[i][i] = (A[i][i] - B[i][r] + 2) % 2;
        }
        int freeNum=Gauss(n,n);//获取自由元
        if(freeNum == -1) continue;
        ans = (ans  *  poww(2 , freeNum)) % mod;
    }
    printf ("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hddddh/article/details/111828336
今日推荐