BZOJ 4031: [HEOI2015]小Z的房间

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=4031

矩阵树定理。 基尔霍夫矩阵就是对于i=j,a[i][j]=d[i],对于i!=j,a[i][j]=a[j][i]=-1(如果可以连边的话),否则就是0。

然后把这个矩阵去掉第i行第i列,解这个行列式(删掉第n行比较方便嘛。。)

模数比较坑爹,并不是一个质数,所以辗转相除。

#include<string>
#include<iostream>
#include<algorithm>
#include<cstdio>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define ll long long
#define maxn 109
#define mm 1000000000
using namespace std;
int n,m,p[maxn][maxn],idx;
char s[maxn][maxn];
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
ll ans,a[maxn][maxn];
int read(){
    int x=0,f=1; char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
bool jud(int x,int y){
    if (x<1||x>n||y<1||y>m||s[x][y]!='.') return 0;
    return 1;
}
ll det(int n){
    rep(i,1,n) rep(j,1,n) a[i][j]=(a[i][j]+mm)%mm;
    ll f=1;
    rep(i,1,n) {
        rep(j,i+1,n) {
            if (a[j][i]==0) continue;
            ll A=a[i][i],B=a[j][i];
            while (B){
                ll t=A/B; A%=B; swap(A,B);
                rep(k,i,n) a[i][k]=(a[i][k]-a[j][k]*t%mm+mm)%mm;
                rep(k,i,n) swap(a[i][k],a[j][k]);
                f=-f;
            }
        }
        if (a[i][i]==0) return 0;
        ans=ans*a[i][i]%mm;
    }
    if (f==-1) ans=((mm-ans)%mm+mm)%mm;
    return ans;
}
int main(){
    n=read(); m=read();
    rep(i,1,n) scanf("%s",s[i]+1);
    rep(i,1,n) rep(j,1,m) if (s[i][j]=='.') p[i][j]=++idx;
    rep(i,1,n) rep(j,1,m) if (s[i][j]=='.'){
        rep(k,0,3) {
            int x=i+dx[k],y=j+dy[k];
            if (jud(x,y)) {
                int u=p[i][j],v=p[x][y];
                a[u][u]++; a[u][v]--; 
            }
        }
    }
    ans=1;
    printf("%lld\n",det(idx-1));
    return 0;
}

 

posted on 2016-01-01 17:31  ctlchild  阅读(162)  评论(0编辑  收藏  举报

导航