在ditoly的帮助下搞懂了矩阵-树定理,想找一道题做做。spoj上有裸题,却翻不了墙,找了好久终于找到了bzoj上的一道 哈哈。
--------------------------------------
题目:给定一个矩阵,有一些格子是柱子,一些是房间。你可以打穿一些墙让相邻的房间可以联通,但是必须满足任意两个房间只有一条通路,求方案数量mod 。 n,m <=9
题解:很裸的矩阵-树定理题目,但是模数不是质数,去看了一下题解,发现可以辗转相除,真的妙。
#include<iostream> #include<cstdio> #define MN 100 #define mod 1000000000LL #define eps 1e-8 #define ll long long using namespace std; int read() { int 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*10+ch-'0'; ch=getchar();} return x*f; } ll s[MN][MN]; int n,m,tot=0,id[MN][MN]; char st[MN][MN]; ll gauss() { ll ans=1,mark=1;int i,j,k; for(int i=1;i<=tot;i++) for(int j=1;j<=tot;j++) if(s[i][j]<0)s[i][j]+=mod; for(i=1;i<=tot;i++) { for(j=i;j<=tot;j++) if(s[j][i]>eps) { if(i!=j) { mark=-mark; for(k=i;k<=tot;k++) swap(s[i][k],s[j][k]); } break; } if(j>tot)continue; for(j=i+1;j<=tot;j++) { while(s[j][i]) { ll x=s[j][i]/s[i][i]; for(k=i;k<=tot;k++) s[j][k]=(s[j][k]+mod-x*s[i][k]%mod)%mod; if(!s[j][i]) break; mark=-mark; for(k=i;k<=tot;k++) swap(s[j][k],s[i][k]); } } } for(int i=1;i<=tot;i++) ans=(ans*s[i][i]+mod)%mod; return mark==-1?(mod-ans)%mod:ans%mod; } int main() { n=read();m=read(); for(int i=1;i<=n;i++) scanf("%s",st[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(st[i][j]=='.') id[i][j]=++tot; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(st[i][j]=='.') { if(i!=n&&st[i+1][j]=='.') { int a=id[i][j],b=id[i+1][j]; s[a][a]++;s[b][b]++;s[a][b]--;s[b][a]--; } if(j!=m&&st[i][j+1]=='.') { int a=id[i][j],b=id[i][j+1]; s[a][a]++;s[b][b]++;s[a][b]--;s[b][a]--; } } tot--; printf("%lld",gauss()); return 0; }