1. 程式人生 > >「雅禮集訓 2017 Day5」矩陣

「雅禮集訓 2017 Day5」矩陣

都是 答案 times class its 矩陣 light ron 所有

填坑填坑..

感謝wwt耐心講解啊..

如果要看這篇題解建議從上往下讀不要跳哦..


30pts

把$A$和$C$看成$n$個$n$維向量,那$A_i$是否加入到$C_j$中就可以用$B_{i,j}$表示了

枚舉矩陣$A$,求出它的秩$r$,如果$C$在$A$的線性空間內則$C$可以被$A$表示出來

那麽$B$矩陣的方案數就是$(2^{n-r})^n$

這時候我們可以發現,由於枚舉$A$覆蓋了所有情況,秩相同的$C$的答案都是一樣的

然後就可以打表算答案了..


60pts

如果不想看可以跳過這段

考慮用dp來代替上面枚舉

定義$f_{i,j,k}$表示已經算了前$i$列,其中$C$有$j$個基在$A$的線性空間裏,$A$有$k$個基在$C$的線性空間外的方案數

那麽答案就是$\sum\limits_{k=1}^{n-r}f[n][r][k](2^{n-r-k})^n$

然後考慮第$i+1$列的情況

1)$j$、$k$都不變,即新的一列在$j+k$個基裏面,方案為$2^{j+k}$

2)$j+1$、$k$不變,$k$不變的方案有$2^{r+k}$,再減去$j$不變的方案就是$2^{r+k}-2^{j+k}$

3)$j$不變,$k+1$,總方案有$2^n$,再減去$k$不變的方案就是$2^n-2^{r+k}$

這樣就得到了一個$O(n^3)$的做法


100pts

30pts時說到,秩相同的$C$的答案都是一樣的

那麽我們不如把所有秩相同的$C$的總答案算起來再除以秩相同的個數

定義$f_{i,j}$表示已經算了前$i$列(也就是$n\times i$的矩陣),秩為$j$的方案數

那麽總答案就是$\sum\limits_{x=r}^n f_{n,x}f_{x,r}(2^{n-x})^n$

再除以秩為$r$的方案數即可..


Code

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <bitset>
#define LL long long
using namespace std;
const LL Maxn = 2010;
const LL Mod = 1e9+7;
bitset <Maxn> a[Maxn];
LL f[Maxn][Maxn];
LL pow2[Maxn], n;
LL pow(LL x, LL k) {
	LL ret = 1;
	while(k){
		if(k&1) ret = (ret*x)%Mod;
		x = (x*x)%Mod;
		k >>= 1;
	}
	return ret;
}
int main() {
	//freopen("mat.in", "r", stdin);
	//freopen("mat.out", "w", stdout);
	LL i, j, k;
	scanf("%lld", &n);
	pow2[0] = 1;
	for(i = 1; i <= n; i++) pow2[i] = (pow2[i-1] << 1) % Mod;
	f[0][0] = 1;
	for(i = 0; i < n; i++){
		for(j = 0; j <= i; j++){
			if(f[i][j] == 0) continue;
			f[i+1][j] = (f[i+1][j] + (f[i][j]*pow2[j])%Mod) % Mod;
			f[i+1][j+1] = (f[i+1][j+1] + (f[i][j]*((pow2[n]-pow2[j]+Mod)%Mod))%Mod) % Mod;
		}
	}
	for(i = 0; i < n; i++){
		for(j = 0; j < n; j++){
			LL x;
			scanf("%lld", &x);
			a[i][j] = x;
		}
	}
	LL r = 0;
	for(i = 0; i < n; i++){
		for(j = r; j <= n; j++){
			if(a[j][i] == 1){ swap(a[r], a[j]); break; }
		}
		if(a[r][i] == 0) continue;
		for(j = r+1; j < n; j++) if(a[j][i] == 1) a[j] ^= a[r];
		r++;
	}
	LL ans = 0;
	for(i = r; i <= n; i++){
		ans = (ans + ((f[n][i]*f[i][r])%Mod*pow(pow2[n], n-i))%Mod)%Mod;
	}
	ans = (ans*pow(f[n][r], Mod-2))%Mod;
	printf("%lld\n", ans);
	return 0;
}

「雅禮集訓 2017 Day5」矩陣