雅礼集训2017day5 矩阵 题解

题目链接:矩阵

一些声明,一般地\(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<<'\n';
	return 0;
}
posted @ 2021-06-01 22:00  y_dove  阅读(167)  评论(2编辑  收藏  举报