题解:
我们考虑一组
的一组合法解中
的关系。
首先 的列向量一定在 的列向量所组成的线性空间里(根据矩阵乘法的过程)。
具体,我们设 的秩为 ,那么合法 的个数就有 个(因为每一列对应一个异或方程组,自由变量都有 个)。
现在我们要统计“秩为 且列向量的线性空间包含 的合法 的个数”。 发现不是很好做,我们可以稍加转化,变为:有序对 ,满足 列向量的线性空间包含 ,且 的秩为 , 的秩为 ,这样一对的贡献为 ,求贡献和。 因为 的秩一样的矩阵是等价的,最后只需要除以秩为 的 的个数即可得到答案。
设 表示 的矩阵,秩为 的方案数,容易发现确定了一个秩为 的矩阵 ,那么 的个数就是 。 因为 也只跟秩有关,那么我们枚举 的秩,贡献和即为 。 的DP很简单,时间复杂度: 。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=2e3+50,mod=1e9+7;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (LL)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
int n,m,f[N][N],pw[N];
bitset <N> A[N];
int main() {
n=rd(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) A[i][j]=rd();
int r=0;
for(int i=1;i<=n;i++) {
int p=r+1,l=p;
for(;l<=n && !A[l][i]; ++l); if(l>n) continue;
if(l!=p) swap(A[l],A[p]);
for(int j=p+1;j<=n;j++) if(A[j][i]) A[j]^=A[p];
++r;
}
pw[0]=1; for(int i=1;i<=n;i++) pw[i]=mul(pw[i-1],2);
f[0][0]=1; for(int i=1;i<=n;i++) for(int j=0;j<=i;j++) f[i][j]=add((j?mul(f[i-1][j-1],dec(pw[n],pw[j-1])):0),mul(f[i-1][j],pw[j]));
int ans=0; for(int x=r;x<=n;++x) ans=add(ans,mul(mul(f[n][x],f[x][r]),power(pw[n-x],n)));
cout<<mul(ans,power(f[n][r],mod-2));
}