bzoj 4031: [HEOI2015]小Z的房间
复习了一下高斯消元求行列式的姿势,……用辗转相除法来消元,
辗转相除法可以用初等行列变换表示,它能将某行的第一个元素快速变小,而且它在模意义下不会出现问题,自然就被用来消元了~
#include <bits/stdc++.h> #define MOD 1000000000 #define N 100 using namespace std; int tot; int S[N][N], in[N][N]; int n, m; char M[N][N]; int solve(int n) { int ans = 1; for (int i = 1; i <= n; ++ i) for (int j = i + 1; j <= n; ++ j) { while (S[j][i]) { int p = S[i][i] / S[j][i]; for (int k = i; k <= n; ++ k) { int q = (S[i][k] - 1ll * p * S[j][k] % MOD + MOD) % MOD; S[i][k] = S[j][k]; S[j][k] = q; } ans *= -1; } } for (int i = 1; i <= n; ++ i) ans = 1ll * ans * S[i][i] % MOD; return (ans + MOD) % MOD; } int add(int a, int b) { S[a][b] --; S[b][a] --; S[a][a] ++; S[b][b] ++; } int di[4] = {0, 1, 0, -1}, dj[4] = {1, 0, -1, 0}; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++ i) scanf("%s", M[i] + 1); for (int i = 1; i <= n; ++ i) for (int j = 1; j <= m; ++ j) if (M[i][j] != '*') in[i][j] = ++ tot; for (int i = 1; i <= n; ++ i) for (int j = 1; j <= m; ++ j) for (int d = 0; d < 2; ++ d) if (i + di[d] <= n && j + dj[d] <= m) if (M[i][j] != '*' && M[i + di[d]][j + dj[d]] != '*') add(in[i][j], in[i + di[d]][j + dj[d]]); printf("%d\n", solve(tot - 1)); }