BZOJ4031: [HEOI2015]小Z的房间

BZOJ4031: [HEOI2015]小Z的房间

https://lydsy.com/JudgeOnline/problem.php?id=4031

分析:

  • 矩阵树定理模板题。
  • 模数非质数,可能不存在逆元,需要用辗转相除的方法把对应项消成\(0\)

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 150
#define mod 1000000000
typedef long long ll;
char mp[N][N];
int idx[N][N],n,m,tot;
int tx[]={0,1,-1,0};
int ty[]={1,0,0,-1};
ll a[N][N];
ll Gauss(int n) {
	int i,j,k,flg=0; ll del,ans=1;
	for(i=1;i<=n;i++) {
		for(j=i;j<=n&&!a[j][i];j++) ;
		if(j>n) continue;
		if(i!=j) {
			for(k=i;k<=n;k++) swap(a[i][k],a[j][k]); 
			flg^=1;
		}
		for(j=i+1;j<=n;j++) {
			while(a[j][i]) {
				del=a[j][i]/a[i][i];
				for(k=i;k<=n;k++) a[j][k]=(a[j][k]-del*a[i][k])%mod;
				if(!a[j][i]) break;
				for(k=i;k<=n;k++) swap(a[i][k],a[j][k]);
				flg^=1;
			}
		}
	}
	for(i=1;i<=n;i++) ans=ans*a[i][i]%mod;
	if(flg) ans=-ans;
	return (ans+mod)%mod;
}
int main() {
	scanf("%d%d",&n,&m);
	int i,j,k;
	for(i=1;i<=n;i++) scanf("%s",mp[i]+1);
	for(i=1;i<=n;i++) {
		for(j=1;j<=m;j++) {
			if(mp[i][j]=='.') {idx[i][j]=++idx[0][0];}
		}
	}
	tot=idx[0][0]; 
	for(i=1;i<=n;i++) {
		for(j=1;j<=m;j++) if(mp[i][j]=='.') {
			int x=i,y=j;
			for(k=0;k<4;k++) {
				int dx=x+tx[k], dy=y+ty[k];
				if(dx>=1&&dx<=n&&dy>=1&&dy<=m&&mp[dx][dy]=='.') {
					a[idx[x][y]][idx[x][y]]++;
					a[idx[x][y]][idx[dx][dy]]--;
				}
			}
		}
	}
	printf("%lld\n",Gauss(tot-1));
}

posted @ 2019-01-06 16:23  fcwww  阅读(124)  评论(0编辑  收藏  举报