「BZOJ4031」[HEOI2015]小Z的房间
矩阵树定理
注意模数不是质数,不能用逆元
用了一种类似辗转相除的方法,非常巧妙
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int N=110,mod=1e9,dx[4]={-1,0,1,0},dy[4]={0,-1,0,1}; 5 int n,m,id[15][15],cnt,w=1; 6 ll mat[N][N],ans=1; 7 inline void add_edge(int f,int t){ 8 mat[f][t]-=1,mat[f][f]+=1; 9 return; 10 } 11 void gauss(){ 12 for(int i=1;i<=cnt;i++) 13 for(int j=1;j<=cnt;j++) mat[i][j]=(mat[i][j]+mod)%mod; 14 int nxt; 15 for(int i=1;i<=cnt;i++){ 16 for(int j=i+1;j<=cnt;j++){ 17 while(mat[j][i]){ 18 ll temp=mat[i][i]/mat[j][i]; 19 for(int k=i;k<=cnt;k++){mat[i][k]=((mat[i][k]-temp*mat[j][k])%mod+mod)%mod;swap(mat[i][k],mat[j][k]);} 20 w=-w; 21 } 22 } 23 if(!mat[i][i]) return; 24 } 25 return; 26 } 27 int main(){ 28 int nxtx,nxty; 29 char c[15]; 30 scanf("%d%d",&n,&m); 31 for(int i=1;i<=n;i++){ 32 scanf("%s",c+1); 33 for(int j=1;j<=m;j++) if(c[j]=='.') id[i][j]=++cnt; 34 } 35 for(int i=1;i<=n;i++){ 36 for(int j=1;j<=m;j++)if(id[i][j]){ 37 for(int d=0;d<4;d++){ 38 nxtx=i+dx[d],nxty=j+dy[d]; 39 if(nxtx>=1&&nxtx<=n&&nxty>=1&&nxty<=m&&id[nxtx][nxty]) add_edge(id[i][j],id[nxtx][nxty]); 40 } 41 } 42 } 43 cnt--; 44 gauss(); 45 for(int i=1;i<=cnt;i++) ans=(ans*mat[i][i])%mod; 46 ans=((ans*w)%mod+mod)%mod; 47 printf("%lld",ans); 48 return 0; 49 }