#矩阵树定理,高斯消元#洛谷 4111 [HEOI2015]小 Z 的房间

题目


分析

题目要求生成树个数,求出基尔霍夫矩阵后高斯消元,
但是这里模数不是质数,所以要辗转相除法


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <cmath>
#define rr register
using namespace std;
const int mod=1000000000; typedef long long lll;
int a[82][82],CNT,n,m,rk[82][82];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void Mo(int &x,int y){x=x<y?x-y+mod:x-y;}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline void add(int x,int y){++a[x][x],++a[y][y],Mo(a[x][y],1),Mo(a[y][x],1);}
inline void doit(int t1,int t2,lll &ai,lll &aj,lll &Ai,lll &Aj,int &F){
	ai=Aj=1,aj=Ai=0;
	while (t2){
		ai-=t1/t2*Ai,aj-=t1/t2*Aj,t1%=t2,
		ai=(ai%mod+mod)%mod,aj=(aj%mod+mod)%mod;
		swap(t1,t2),swap(ai,Ai),swap(aj,Aj),F=mod-F;
	}
}
inline signed Gauss(int n){
	rr int ans=1; rr lll ai,aj,Ai,Aj;
    for (rr int i=1;i<=n;++i){
        for (rr int j=i+1;j<=n;++j){
		    rr int t1=a[i][i],t2=a[j][i];
		    doit(t1,t2,ai,aj,Ai,Aj,ans);
		    for (rr int k=1;k<=n;++k){
		    	rr int T1=mo(a[i][k]*ai%mod,a[j][k]*aj%mod);
		    	rr int T2=mo(a[i][k]*Ai%mod,a[j][k]*Aj%mod);
		    	a[i][k]=T1,a[j][k]=T2;
			}
        }
        ans=1ll*ans*a[i][i]%mod;
    }
	return ans;
}
signed main(){
	n=iut(); m=iut();
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=m;++j){
	    rr char c=getchar();
		while (c!='*'&&c!='.') c=getchar();
		if (c=='.') rk[i][j]=++CNT;
	}
	for (rr int i=1;i<=n;++i)
	for (rr int j=1;j<=m;++j)
	if (rk[i][j]){
		if (j<m&&rk[i][j+1]) add(rk[i][j],rk[i][j+1]);
		if (i<n&&rk[i+1][j]) add(rk[i][j],rk[i+1][j]); 
	}
	return !printf("%d",Gauss(CNT-1));
}
posted @ 2020-11-03 20:06  lemondinosaur  阅读(58)  评论(0编辑  收藏  举报