第 45 屆國際大學生程式設計競賽(ICPC)亞洲區域賽(濟南)A. Matrix Equation(高斯消元)
連結:https://ac.nowcoder.com/acm/contest/10662/A
來源:牛客網
We call a matrix "01 Square" if and only if it's a N×NN×N matrix and its elements are all 00 or 11.
For two 01 Squares XX,YY, we define two operators X×YX×Y and X⊙YX⊙Y. The value of them are also 01 Square matrices and calculated below(we use ZZ to abbreviate X×YX×Y and DD to abbreviate X⊙YX⊙Y):
Zi,j=(∑k=1NXi,kYk,j) mod 2Zi,j=(∑k=1NXi,kYk,j) mod 2
Di,j=Xi,jYi,jDi,j=Xi,jYi,j
Now MianKing has two 01 Squares A,BA,B, he wants to solve the matrix equation below:
A×C=B⊙CA×C=B⊙C
You need to help MainKing solve this problem by calculating how many 01 Squares CC 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 NN
Then there are NN lines and each line has NN integers, the j-th integer of the i-th line denotes Ai,jAi,j
Then there are NN lines and each line has NN integers, the j-th integer of the i-th line denotes Bi,jBi,j
1≤N≤2001≤N≤200, Ai,j,Bi,j∈{0,1}Ai,j,Bi,j∈{0,1}
輸出描述:
Output the answer module 998244353998244353.
示例1
輸入
複製
2
0 1
1 1
1 0
0 1
輸出
複製
2
示例2
輸入
複製
3
1 0 0
0 1 0
0 0 1
1 1 1
1 1 1
1 1 1
輸出
複製
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
輸出
複製
8
比賽的時候沒學線代相關的演算法,現在看的話其實還是挺套路的2333
首先不難寫出每個\(c_{ij}\)要滿足的等式:
\(\Sigma_{i = 1}^{n}A_{ik}C_{kj} = B_{ij}C_{ij}\),同時注意到這個加法是在模2意義下的加法,因此其本質就是異或運算,那麼這個等式可以寫為:
\(\bigoplus_{i = 1}^{n}A_{ik}C_{kj} = B_{ij}C_{ij}\)。右邊那一項含有要求的變元,同時\(C_{ij}\)正好也在左式,因此要把它移到左邊。在左式中與\(B_{ij}C_{ij}\)對應的實際上是\(A_{ii}C_{ij}\),所以如果\(A_{ii} == B_{ij}\),那麼移項後\(C_{ij}\)的係數實際上就是0了(兩邊同時異或上\(A_{ii}C_{ij}\));同理如果\(A_{ii} != B_{ij}\),那麼移項後\(C_{ij}\)的係數實際上就是1。
矩陣C是列獨立的,這樣,我們取C矩陣的某一列(設為\(C_{i})\)作為列向量與A相乘:\(A\times C_{i} = B_{i}⊙C_{i}\),再移項實際上就是n個異或方程組,解出來的自由元的個數就是C的這一列能任意取值(0或1)的位置的個數,這樣對於C的每一列都求出來自由元的個數,最終能夠得到自由元的總數x,輸出的答案就是\(2^x\)。
求解異或方程組可以用bitset優化的高斯消元來做。
#include <bits/stdc++.h>
#define mod 998244353
#define int long long
using namespace std;
int n, a[205][205], b[205][205], m[205][205];
long long fpow(long long a, long long b) {
long long ans = 1;
for(; b; b >>= 1) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
}
return ans % mod;
}
bitset<220> M[205];
int Free;
int guass(int n, int m)//n row n 行 m col m 列
{
Free = 0;
int row = 0, col = 0, maxx;
for(; col < m; ++ col) {
for(maxx = row; maxx < n; ++ maxx)
if(M[maxx][col])
break;
if(maxx == n) continue;
if(M[maxx][col] == 0) continue;
swap(M[maxx], M[row]);
for(int i = row + 1; i < n; ++ i)
if(M[i][col]) //如果這一列有數的話那一行全部消掉
M[i] = M[i] ^ M[row];
row ++ ;
}
Free = n - row;
if(row < n) {
for(int i = row; i < n; ++ i)
if(M[i][m])//矛盾,出現非零的常數項等於0,說明無解
return 2;
return 1;//有無窮多組解
}
//行最簡形矩陣,第i行第i列的表示的未知量x_i的一個解
for(int i = n - 1; i >= 0; -- i) {//第i行,第i行第i列
for(int j = i + 1; j < m; ++ j)//第j列,右邊所有列都要消
M[i][m] = M[i][m] ^ (M[j][m] * M[i][j]);
}
return 0;
}
signed main() {
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
cin >> b[i][j];
}
}
long long ans = 1, num = 0;
for(int j = 1; j <= n; j++) {//求c1j c2j ... cnj中的自由元個數
for(int i = 1; i <= n; i++) {
for(int k = 1; k <= n; k++) {
m[i][k] = a[i][k];
}
if(b[i][j] == a[i][i]) {
m[i][i] = 0;//相當於移項
} else {
//b[i][j]為0的話不影響
m[i][i] = 1;
}
}
//此時對m矩陣進行高斯消元解異或方程組,求自由元個數
//cout << endl << endl;
for(int ii = 1; ii <= n; ii++) {
for(int jj = 1; jj <= n; jj++) {
M[ii - 1][jj - 1] = m[ii][jj];
}
}
int result = guass(n, n);
if(result == 2) {
cout << 0;
return 0;
}
num += Free;
Free = 0;
}
ans = fpow(2, num);
cout << ans;
return 0;
}