题目链接:矩阵
一些声明,一般地(r(A),A in matrix)表示矩阵A的秩
线性代数好题
我们考虑枚举(A,B)有多少组解
首先我们可以把 C , B 看成 n 个互不相关的列向量,考虑若有解,则C的每一个列向量都在A构成的线性空间内(C的任意一个向量,都可以理解为A的线性组合,系数是对应B的列向量)
那么我们考虑(r(A) = x),那么B的每一列对应的方案有(2^{n - r(A)})(对应基的位置是确定,其他可以乱选)
以下证明一个引理,如果我们把秩大小相同的矩阵归为一个等价类,那么等价类中的任意一个矩阵 C ,对应的方案数 (A,B) 都相等
首先,如果两个线性无关组本质相同,那么对应的方案 (A,B) 显然相同
否则,假设A的秩为 x ,相当于已经钦定了 r 个无关向量,然后要在剩余的 n-r 列中构造 x-r 个线性无关向量组,注意到若r相同,n-r,x-r以及r构成的线性空间大小 (2^r) 这些变量都相同,故方案数相同
那么我们可以设(f(i,j))表示现在有i个长为n的列向量,秩为j的方案数
考虑枚举(A)的秩 x ,设其代表的线性无关组为({k_1,k_2.....k_x}),因为C的任意列向量都可以表示为该线性无关组的线性组合,那么我们就可以把它压缩成长为 x 的(0,1)向量,第 i 位为0/1,就表示(k_i)的系数为0/1,又因为秩是 r ,所以若 A 的秩确定为 x , C 的方案便是 (f(x,r))
所以(ans = frac{sum_{x = r(C)}^nf(x,r(C)) * f(n,x)}{f(n,r(C))})
至于 r(C) 怎么算,可以异或高斯消元
复杂度 (O(frac{n^3}{omega} + n^2))
/*C*/
#include<bits/stdc++.h>
using namespace std;
int read(){
char c = getchar();
int x = 0;
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar();
return x;
}
const int _ = 2e3 + 7;
int f[_][_];
bitset<_>C[_],p[_];
int pw[_*_];int r = 0;int n;
const int mod = 1e9 + 7;
void add(int &x,int y){
x += y - mod;
x += (x >> 31) & mod;
}
void ins(bitset<_> A){
for(int i = n; i >= 1; --i){
if(A[i] == 0) continue;
if(p[i].count() == 0){
p[i] = A;
r++;
return;
}
else A ^= p[i];
}
}
int qpow(int x,int y){
int ans = 1;
while(y){
if(y & 1) ans = 1ll * ans * x % mod;
x = 1ll * x * x % mod;
y >>= 1;
}
return ans;
}
int main(){
n = read();
pw[0] = 1;
for(int i = 1; i <= n * n; ++i) pw[i] = (pw[i-1] << 1) % mod;
f[0][0] = 1;
for(int i = 0; i < n; ++i){
for(int j = 0; j <= n; ++j){
if(!f[i][j]) continue;
int v = f[i][j];
add(f[i+1][j],1ll * v * pw[j] % mod);
add(f[i+1][j+1],1ll * v * (pw[n] - pw[j] + mod) % mod);
}
}
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j)
C[i][j] = read();
ins(C[i]);
}
int ans = 0;
for(int x = r; x <= n; ++x) add(ans,1ll * f[n][x] * f[x][r] % mod * pw[(n-x)*n] % mod);
ans = 1ll * ans * qpow(f[n][r],mod - 2) % mod;
cout<<ans<<'
';
return 0;
}