uoj#453. 【集训队作业2018】围绕着我们的圆环(线性代数+递推)

题面

传送门

题解

我对线代一无所知

如果下面有啥说错的地方请说出来省的我一辈子都搞不明白

如果你没看懂以下在讲什么不要紧,因为我也没看懂

首先,关于\(A\times B \equiv C \pmod{2}\)的方程的一组合法解,\(C\)的列向量必定在\(A\)的列向量的线性空间里

那么\(B\)就可以看成一个方程组……

\(A\)的秩为\(x\),那么\(B\)的合法的解的个数就是\((2^{q-x})^s\)

大概意思就是说因为\(A\)的秩只有\(x\),每一列对应一个异或方程组,有\(q-x\)个自由元

我们需要统计\((A,C)\),其中\(C\)的列向量在\(A\)的列向量的线性空间中,且\(A\)的秩为\(x\)\(C\)的秩为\(r\),这一组的贡献要乘上一个\((2^{q-x})^s\)。然后发现所有秩为\(r\)\(C\)是等价的,只要最后除以秩为\(r\)\(C\)的个数就行了

所以要怎么数啊……我实在看不太懂啊……

\(f_{i,j}\)表示\(p\times i\)的矩阵,秩为\(j\)的方案数,\(g_{i,j}\)表示\(i\times s\)的矩阵,秩为\(j\)的方案数,递推的方式比较简单,看代码应该能懂这里就不讲了

所以如果我们确定了\(A\)的秩\(x\),以及\(C\)的秩\(r\),那么\((A,C)\)的数量就为\(g_{x,r}\)(感性理解一下好了……)

所以如果我们确定了\(C\)的秩\(r\),答案就是\(\sum_{i=r}^q f_{q,i}g_{i,r}\)

对于每一个\(r\)记录答案就是了

然而这里需要我们动态维护矩阵\(C\)的秩诶?

大概就是一个线性基吧……把\(C\)给放进一个线性基里,每次修改一行的时候先删除。删除就是把线性基里所有包含这一行的元素删除这一行的贡献。如果某一个元素只有这一行,那么说明删去这一行之后矩阵的秩会减\(1\)

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
inline int get(){R char ch;while((ch=getc())>'9'||ch<'0');return ch-'0';}
char sr[1<<21],z[25];int K=-1,Z=0;
inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
void print(R int x){
	if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
	while(z[++Z]=x%10+48,x/=10);
	while(sr[++K]=z[Z],--Z);sr[++K]='\n';
}
const int N=1005,P=1e9+7;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R ll y){
    R int res=1;
    for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
    return res;
}
bitset<N>a[N],b[N];int bin[N],id[N],pos[N],f[N][N],g[N][N],ans[N];
int p,q,s,m,k,las,r,n,res;
void ins(R int i){
	fd(j,s,1)if(a[i][j]){
		if(!id[j]){++r,id[j]=i,pos[i]=j;return;}
		a[i]^=a[id[j]],b[i]^=b[id[j]];
	}
	pos[i]=0;
}
int erase(int i){
	int mn=s+1,x=0;
	fp(j,1,p)if(b[j][i]&&cmin(mn,pos[j]))x=j;
	fp(j,1,p)if(b[j][i]&&j!=x)a[j]^=a[x],b[j]^=b[x];
	if(pos[x])--r,id[pos[x]]=0,pos[x]=0;
	a[x].reset(),b[x].reset();
	return x;
}
void init(){
	n=N-1;
	bin[0]=1;fp(i,1,n)bin[i]=mul(bin[i-1],2);
	f[0][0]=g[0][0]=1;
	fp(i,1,n)fp(j,0,i){
		f[i][j]=add((j?mul(f[i-1][j-1],dec(bin[p],bin[j-1])):0),mul(f[i-1][j],bin[j]));
		g[i][j]=add((j?mul(g[i-1][j-1],dec(bin[s],bin[j-1])):0),mul(g[i-1][j],bin[j]));
	}
	for(R int i=1,S=bin[s];i<=n;++i)bin[i]=mul(bin[i-1],S);
	fp(r,0,s){
		res=0;
		fp(i,r,q)res=add(res,1ll*f[q][i]*g[i][r]%P*bin[q-i]%P);
		ans[r]=mul(res,ksm(g[p][r],P-2));
	}
}
int main(){
//	freopen("testdata.in","r",stdin);
	p=read(),q=read(),s=read(),m=read(),k=get();
	init();
	fp(i,1,p){
		fp(j,1,s)a[i][j]=get();
		b[i][i]=1,ins(i);
	}
	print(las=ans[r]);
	while(m--){
		int j=read()^(las*k),x=erase(j);
		fp(i,1,s)a[x][i]=get();
		b[x][j]=1,ins(x),print(las=ans[r]);
	}
	return Ot(),0;
}
posted @ 2019-03-05 20:46  bztMinamoto  阅读(434)  评论(0编辑  收藏  举报
Live2D