2020 ICPC 济南 A Matrix Equation (高斯消元)

题目链接A-Matrix Equation 第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南)

题目描述

We call a matrix "01 Square" if and only if it's a matrix and its elements are all or .

For two 01 Squares , , we define two operators and . The value of them are also 01 Square matrices and calculated below(we use to abbreviate and to abbreviate ):





Now MianKing has two 01 Squares , he wants to solve the matrix equation below:



You need to help MainKing solve this problem by calculating how many 01 Squares satisfy this equation.

The answer may be very large, so you only need to output the answer module .



输入描述:

The first line has one integer 

Then there are lines and each line has integers, the j-th integer of the i-th line denotes

Then there are lines and each line has integers, the j-th integer of the i-th line denotes

,

输出描述:

Output the answer module .
示例1

输入

复制 2 0 1 1 1 1 0 0 1
2
0 1
1 1
1 0
0 1

输出

复制 2
2
示例2

输入

复制 3 1 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1
3
1 0 0
0 1 0
0 0 1
1 1 1
1 1 1
1 1 1

输出

复制 512
512
示例3

输入

复制 4 0 1 0 1 0 1 1 0 0 1 1 1 1 0 0 1 1 0 1 1 0 1 1 1 1 0 0 1 1 1 1 0
4
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 1
1 0 1 1
0 1 1 1
1 0 0 1
1 1 1 0

输出

复制 8
8

题目大意

给你定义两种01矩阵上的运算:

X i , j × Y i , j = ( ∑ k = 1 N X i , j Y i , j ) X_{i,j}×Y_{i,j}=(\sum^N_{k=1}X_{i,j}Y_{i,j}) Xi,j×Yi,j=(k=1NXi,jYi,j)

X i , j ⊙ Y i , j = X i , j Y i , j X_{i,j}⊙Y_{i,j}=X_{i,j}Y_{i,j} Xi,jYi,j=Xi,jYi,j

然后给你两个01方阵A和B,求满足下式的01方阵C有多少种。

A × C = B ⊙ C A×C=B⊙C A×C=BC

分析

思考下上面的式子可以发现C的每一列的结果都是独立的。都是由n个下面的方程组成

∑ k = 0 n − 1 A i , k C k , j = B i , j C i , j \sum_{k=0}^{n-1} A_{i,k}C_{k,j}=B_{i,j}C_{i,j} k=0n1Ai,kCk,j=Bi,jCi,j

再分别讨论A,B的取值

A i , i = B i , j A_{i,i}=B_{i,j} Ai,i=Bi,j:除 C i , j C_{i,j} Ci,j外有偶数个值为1

A i , i ≠ B i , j A_{i,i}\neq B_{i,j} Ai,i=Bi,j:包括 C i , j C_{i,j} Ci,j,总共有奇数个值为1

可惜见识少,没用过高斯消元这种东西,推到这儿就卡死了。赛后一学发现这不板子题嘛。怪不得一百多人做出来了。

参考资料:线性代数 —— 高斯消元法

重新思考:尝试来构建异或线性方程组。

∑ k = 0 n − 1 A i , k C k , j = B i , j C i , j \sum_{k=0}^{n-1} A_{i,k}C_{k,j}=B_{i,j}C_{i,j} k=0n1Ai,kCk,j=Bi,jCi,j

A i , i = B i , j A_{i,i}=B_{i,j} Ai,i=Bi,j:此时让等式右端为0, A i , i = 0 A_{i,i}=0 Ai,i=0

A i , i ≠ B i , j A_{i,i}\neq B_{i,j} Ai,i=Bi,j:此时让等式右端为0, A i , i = 1 A_{i,i}=1 Ai,i=1

然后2^自由元总数即为答案个数。

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N=210;


int a[N][N];//增广矩阵
int x[N];//解集
int freeX[N];//自由变元
int freeX[N];//自由变元
// equ:方程个数 var:变量个数
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 k;//当前处理的行
	for(k=0;k<equ&&col<var;k++,col++){//枚举当前处理的行
		int maxr=k;//当前列绝对值最大的行
		for(int i=k+1;i<equ;i++){//寻找当前列绝对值最大的行
			if(a[i][col]>a[maxr][col]){
				maxr=i;
				swap(a[k],a[maxr]);//与第k行交换
				break;
			}
		}
		if(a[k][col]==0){//col列第k行以下全是0,处理当前行的下一列
			freeX[num++]=col;//记录自由变元
			k--;
			continue;
		}
 
		for(int i=k+1;i<equ;i++){
			if(a[i][col]!=0){
				for(int j=col;j<var+1;j++){//对于下面出现该列中有1的行,需要把1消掉
					a[i][j]^=a[k][j];
				}
			}
		}
	}
 
	/*求解*/
	//无解:化简的增广阵中存在(0,0,...,a)这样的行,且a!=0
	for(int i=k;i<equ;i++)
		if(a[i][col]!=0)
			return -1;
 
	//无穷解: 在var*(var+1)的增广阵中出现(0,0,...,0)这样的行
	if(k<var)//返回自由变元数
		return var-k;//自由变元有var-k个
 
	//唯一解: 在var*(var+1)的增广阵中形成严格的上三角阵
	for(int i=var-1;i>=0;i--){//计算解集
		x[i]=a[i][var];
		for(int j=i+1;j<var;j++)
			x[i]^=(a[i][j]&&x[j]);
	}
	return 0;
}


void testf(){
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			cin>>a[i][j];
		}
	}
	cout<<Gauss(3,3);
	exit(0);
}


int A[N][N];
int B[N][N];
const long long MOD=998244353;
int main(){
	//testf();
	
	ios::sync_with_stdio(0);
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			cin>>A[i][j];
		}
	}
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			cin>>B[i][j];
		}
	}
	long long ans_cnt=0;
	for(int j=0;j<n;j++){
		for(int i=0;i<n;i++){
			for(int k=0;k<n;k++){
				a[i][k]=A[i][k];
			}
			a[i][n]=0;
			a[i][i]=(A[i][i]==B[i][j]?0:1);
		}


		int cnt=Gauss(n,n);
		if(cnt>0){
			ans_cnt+=cnt;
		}
		else if(cnt<0){
			cout<<0;
			return 0;
		}
	}
	long long ans=1;
	while(ans_cnt--){
		ans<<=1;
		ans%=MOD;
	}
	cout<<ans;
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值