「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 }

 

posted @ 2018-03-08 13:28  Cupcake  阅读(93)  评论(0编辑  收藏  举报