Loading

题解 P4111 [HEOI2015]小 Z 的房间

题解

题目大意:给定一个无向图,求它的生成树个数。

一道裸的矩阵树定理,外加一些建图的技巧。

矩阵树定理

对于一个 \(Laplace\) 矩阵,其去掉任意一行后的行列式即为答案。

行列式不会的看这里

\(Laplace\) 矩阵是一个无向图的邻接矩阵转化而来的,其中 \(L_{i,i}\) 代表 \(i\) 的度数,\(L_{i,j}\) 代表 \(i->j\) 有多少条路径(准确的说是这些路径的权值和,求生成树时设为 \(1\) )。

至于怎么算,看这里

那么有了这些知识,我们就可以 \(A\) 了这题。

注意,这题中模数不是质数,不能求逆元,所以我们消元时要用辗转相除法,所以真正的时间复杂度为 \(\mathcal O((nm)^3log_{nm})\)

Code

\(AC \kern 0.5emCODE:\)

#include<bits/stdc++.h>
#define ri register signed
#define p(i) ++i
using namespace std;
namespace IO{
    char buf[1<<21],*p1=buf,*p2=buf;
    #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++
    inline int read() {
        ri x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*f; 
    }
}
using IO::read;
namespace nanfeng{
    #define int long long
    #define cmax(x,y) ((x)>(y)?(x):(y))
    #define cmin(x,y) ((x)>(y)?(y):(x))
    #define FI FILE *IN
    #define FO FILE *OUT
    static const int MOD=1e9,N=15;
    int id[N][N],G[N*N][N*N],deg[N*N],n,m,cnt,ans=1;
    char h[N][N];
    inline void add(int u,int v) {G[u][v]=G[v][u]=1;}
    inline int main() {
        // FI=freopen("nanfeng.in","r",stdin);
        // FO=freopen("nanfeng.out","w",stdout);
        n=read(),m=read();
        for (ri i(1);i<=n;p(i)) {
            scanf("%s",h[i]+1);
            for (ri j(1);j<=m;p(j)) if (h[i][j]=='.') id[i][j]=p(cnt); 
        }
        for (ri i(1);i<=n;p(i)) {
            for (ri j(1);j<=m;p(j)) {
                if (id[i][j]&&id[i][j-1]) add(id[i][j],id[i][j-1]);
                if (id[i][j]&&id[i-1][j]) add(id[i][j],id[i-1][j]);
            }
        }
        for (ri i(1);i<=cnt;p(i)) {
            for (ri j(1);j<=cnt;p(j)) if (G[i][j]) p(deg[i]);
        }
        for (ri i(1);i<=cnt;p(i)) {
            for (ri j(1);j<=cnt;p(j)) {
                if (i==j) G[i][j]=deg[i];
                else G[i][j]=-G[i][j];
            }   
        }
        cnt-=1;
        for (ri i(1);i<=cnt;p(i)) {//这是高斯消元,要化成三角矩阵,而不要以高斯约旦法消成对角线矩阵。
            for (ri j(i+1);j<=cnt;p(j)) {
                while(G[j][i]) {
                    int k=G[i][i]/G[j][i];
                    for (ri l(i);l<=cnt;p(l)) G[i][l]=(G[i][l]-G[j][l]*k%MOD+MOD)%MOD;
                    swap(G[i],G[j]);
                    ans*=-1;
                }
            }
            ans=(ans*G[i][i]%MOD+MOD)%MOD;
        } //求行列式
        printf("%lld\n",(ans+MOD)%MOD);
        return 0;
    }
    #undef int
}
int main() {return nanfeng::main();}
posted @ 2021-06-13 19:03  ナンカエデ  阅读(34)  评论(0编辑  收藏  举报