BZOJ 4031: [HEOI2015]小Z的房间 [矩阵树定理 行列式取模]
http://www.lydsy.com/JudgeOnline/problem.php?id=4031
裸题........
问题在于模数是$10^9$
我们发现消元的目的是让一个地方为0
辗转相除法也可以做到这一点
只不过取模用减整除来代替就好了
注意本题需要分配$id$,因为柱子不能算
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int N=105,MOD=1e9; inline int read(){ char c=getchar();int x=0; while(c<'0'||c>'9'){c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x; } int n,m,a[N][N]; char s[11][11]; void Gauss(int n){ int s=0; for(int i=1;i<=n;i++){//printf("i %d\n",i); int r=i; for(;r<=n;r++) if(a[r][i]) break; if(r==n+1){puts("0");return;} if(r!=i){ s^=1; for(int k=i;k<=n;k++) swap(a[i][k],a[r][k]); } for(int j=i+1;j<=n;j++) while(a[j][i]){//printf("j %d %d\n",j,a[j][i]); ll t=a[j][i]/a[i][i]; for(int k=i;k<=n;k++) a[j][k]=(a[j][k]-t*a[i][k]%MOD+MOD)%MOD; if(a[j][i]==0) break; s^=1; for(int k=i;k<=n;k++) swap(a[i][k],a[j][k]); } } ll ans=1; for(int i=1;i<=n;i++) ans=ans*a[i][i]%MOD; if(s) ans=(-ans+MOD)%MOD; printf("%lld",ans); } int id[N][N],tot; void buildEquation(){ for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) if(s[i][j]=='.') id[i][j]=++tot; for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) if(id[i][j]){ int u=id[i][j],v; if(i!=1&&s[i-1][j]=='.'){ v=id[i-1][j]; a[u][u]++;a[v][v]++; a[u][v]--;a[v][u]--; } if(j!=1&&s[i][j-1]=='.'){ v=id[i][j-1]; a[u][u]++;a[v][v]++; a[u][v]--;a[v][u]--; } } for(int i=1;i<=m*n;i++) for(int j=1;j<=m*n;j++) a[i][j]=(a[i][j]+MOD)%MOD;//printf("%d%c",a[i][j],j==n?'\n':' '); } int main(){ freopen("in","r",stdin); m=read();n=read(); for(int i=1;i<=m;i++) scanf("%s",s[i]+1); buildEquation();//puts("hi"); Gauss(tot-1); }
Copyright:http://www.cnblogs.com/candy99/