LOJ#6040. 「雅礼集训 2017 Day5」矩阵

传送门

题解:
我们考虑一组 A B C ( mod 2 ) 的一组合法解中 A , C 的关系。

首先 C 的列向量一定在 A 的列向量所组成的线性空间里(根据矩阵乘法的过程)。

具体,我们设 A 的秩为 x ,那么合法 B 的个数就有 ( 2 n x ) n 个(因为每一列对应一个异或方程组,自由变量都有 n x 个)。

现在我们要统计“秩为 x 且列向量的线性空间包含 C 的合法 A 的个数”。 发现不是很好做,我们可以稍加转化,变为:有序对 ( A , C ) ,满足 A 列向量的线性空间包含 C ,且 C 的秩为 r , A 的秩为 x ,这样一对的贡献为 ( 2 n x ) n ,求贡献和。 因为 C 的秩一样的矩阵是等价的,最后只需要除以秩为 r C 的个数即可得到答案。

f i , j 表示 i n 的矩阵,秩为 j 的方案数,容易发现确定了一个秩为 x 的矩阵 A ,那么 C 的个数就是 f x , r 。 因为 A 也只跟秩有关,那么我们枚举 A 的秩,贡献和即为 i = r n f n , i f i , r ( 2 n i ) n f 的DP很简单,时间复杂度: O ( n 2 + n 3 32 )

#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));
}

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/80533951