A题
tag:思维 高斯消元 线性代数
题面
题目描述
We call a matrix “01 Square” if and only if it’s a N×N matrix and its elements are all 00 or 11.
For two 01 Squares XX,YY, we define two operators X×Y and X⊙Y. The value of them are also 01 Square matrices and calculated below(we use Z to abbreviate X×Y and D to abbreviate X⊙Y):
D i , j = X i , j Y i , j D_{i,j}=X_{i,j}Y_{i,j} Di,j=Xi,jYi,j
Now MianKing has two 01 Squares A,B, he wants to solve the matrix equation below:
You need to help MainKing solve this problem by calculating how many 01 Squares C satisfy this equation.
The answer may be very large, so you only need to output the answer module 998244353998244353.
输入
The first line has one integer N
Then there are N lines and each line has N integers, the j-th integer of the i-th line denotes
A
i
,
j
A_{i,j}
Ai,j
Then there are N lines and each line has N integers, the j-th integer of the i-th line denotes
B
i
,
j
B_{i,j}
Bi,j
1≤N≤200,
A
i
,
j
,
B
i
,
j
∈
{
0
,
1
}
A_{i,j},B_{i,j} \in \{0,1\}
Ai,j,Bi,j∈{0,1}
输出
Output the answer module 998244353.
样例输入
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
思路
题意即对于给定01方阵A B找到01方阵C使得:
A
×
C
=
B
⊙
C
A\times C=B\odot C
A×C=B⊙C,问C的种数。
可以发现C的每列均是独立的,所以把每列的种数相乘即为C的种数。以样例为例进行说明:A=
[
0
1
0
1
0
1
1
0
0
1
1
1
1
0
0
1
]
\left[ \begin{matrix}0&1&0&1\\0&1&1&0\\0&1&1&1\\1&0&0&1\\\end{matrix} \right]
⎣⎢⎢⎡0001111001101011⎦⎥⎥⎤,B的第一列=
[
1
0
1
1
]
\left[ \begin{matrix}1\\0\\1\\1\end{matrix} \right]
⎣⎢⎢⎡1011⎦⎥⎥⎤,设C的第一列=
[
x
1
x
2
x
3
x
4
]
\left[ \begin{matrix}x1\\x2\\x3\\x4\end{matrix} \right]
⎣⎢⎢⎡x1x2x3x4⎦⎥⎥⎤,可得:
[
x
2
+
x
4
=
x
1
x
2
+
x
3
=
0
x
2
+
x
3
+
x
4
=
x
3
x
1
+
x
4
=
x
4
]
\left[ \begin{matrix}x2+x4=x1\\x2+x3=0\\x2+x3+x4=x3\\x1+x4=x4\end{matrix} \right]
⎣⎢⎢⎡x2+x4=x1x2+x3=0x2+x3+x4=x3x1+x4=x4⎦⎥⎥⎤,因为是mod 2加法所以相当于做异或:
[
x
2
⨁
x
4
=
x
1
x
2
⨁
x
3
=
0
x
2
⨁
x
3
⨁
x
4
=
x
3
x
1
⨁
x
4
=
x
4
]
\left[ \begin{matrix}x2\bigoplus x4=x1\\x2\bigoplus x3=0\\x2\bigoplus x3\bigoplus x4=x3\\x1\bigoplus x4=x4\end{matrix} \right]
⎣⎢⎢⎡x2⨁x4=x1x2⨁x3=0x2⨁x3⨁x4=x3x1⨁x4=x4⎦⎥⎥⎤,把等式右侧全部化0
[
x
1
⨁
x
2
⨁
x
4
=
0
x
2
⨁
x
3
=
0
x
2
⨁
x
4
=
0
x
1
=
0
]
\left[ \begin{matrix}x1\bigoplus x2\bigoplus x4=0\\x2\bigoplus x3=0\\x2\bigoplus x4=0\\x1=0\end{matrix} \right]
⎣⎢⎢⎡x1⨁x2⨁x4=0x2⨁x3=0x2⨁x4=0x1=0⎦⎥⎥⎤,转化为矩阵表示:
[
x
1
x
2
x
3
x
4
1
1
0
1
0
1
1
0
0
1
0
1
1
0
0
0
]
\left[ \begin{matrix}x1&x2&x3&x4\\1&1&0&1\\0&1&1&0\\0&1&0&1\\1&0&0&0\\ \end{matrix} \right]
⎣⎢⎢⎢⎢⎡x11001x21110x30100x41010⎦⎥⎥⎥⎥⎤,求矩阵的秩r,n-r即为此列中可自由取值的变量个数,每个变量可取0 or 1,所以此列的种数:
2
n
−
r
2^{n-r}
2n−r,所有列种数的乘积取模即为答案。
采用高斯消元法求矩阵的秩,由于是异或操作,采用特殊的数据结构:biset进行存储以加速运算。(高斯消元法,即线性代数中学的通过简单行变换化阶梯矩阵,注意:在此过程中,当某列之下所有元素均为0时,行不变,列向右移动一位)。
附,上例运算过程:
[
1
1
0
1
0
1
1
0
0
1
0
1
1
0
0
0
]
\left[ \begin{matrix} \pmb{1}&\pmb{1}&\pmb{0}&\pmb{1}\\0&1&1&0\\0&1&0&1\\\pmb{1}&0&0&0\\ \end{matrix} \right]
⎣⎢⎢⎡11100111111110000100111010⎦⎥⎥⎤,第四行与第一行做异或
→
\rightarrow
→
[
1
1
0
1
0
1
1
0
0
1
0
1
0
1
0
1
]
\left[ \begin{matrix} 1&1&0&1\\\pmb{0}&\pmb{1}&\pmb{1}&\pmb{0}\\0&\pmb{1}&0&1\\0&\pmb{1}&0&1\\ \end{matrix} \right]
⎣⎢⎢⎡1000001111111111011100100011⎦⎥⎥⎤,第三、四行与第二行做异或
→
\rightarrow
→
[
1
1
0
1
0
1
1
0
0
0
1
1
0
0
1
1
]
\left[ \begin{matrix}1&1&0&1\\0&1&1&0\\\pmb{0}&\pmb{0}&\pmb{1}&\pmb{1}\\0&0&\pmb{1}&1\\ \end{matrix} \right]
⎣⎢⎢⎡10000011000001111111101111⎦⎥⎥⎤,第四行与第三行做异或
→
\rightarrow
→
[
1
1
0
1
0
1
1
0
0
0
1
1
0
0
0
0
]
\left[ \begin{matrix}1&1&0&1\\0&1&1&0\\0&0&1&1\\\pmb{0}&\pmb{0}&\pmb{0}&\pmb{0} \end{matrix} \right]
⎣⎢⎢⎡100000110000011000101000⎦⎥⎥⎤.所以该矩阵秩为3,自由取值变量个数为1,种数为2.
源码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=998244353;
ll qpow(ll a,ll p){
ll ans=1;
while(p){
if(p&1) ans=ans*a%mod;
a=a*a%mod;
p>>=1;
}
return ans;
}
int A[205][205],B[205][205];
bitset<205> a[205];
ll guass(int n){
for(int i=1,p=1;i<=n;i++){
if(!a[p][i]){
for(int j=p+1;j<=n;j++){
if(a[j][i]) {swap(a[p],a[j]);break;}
}
}
if(!a[p][i]) continue;//当目前列全部为0时,列右移,行不动;p为行,i为列。
for(int j=p+1;j<=n;j++){
if(a[j][i]) a[j]^=a[p];
}
p++;
}
int ans=0;
for(int j=n;j>=1;j--){
if(a[j].none()) ans++;
else break;
}
return ans;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&A[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&B[i][j]);
}
}
ll ans=0;
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[i][j]=A[i][j];
}
if(B[i][k]) a[i][i]=a[i][i]^1;
}
ans+=guass(n);
//printf("guass:%d\n",guass(n));
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++){
// cout<<a[i][j];
// }printf("\n");
// }printf("\n");
}
printf("%lld\n",qpow(2,ans));
return 0;
}