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));
}

 

posted @ 2017-01-10 21:40  AwD!  阅读(365)  评论(0编辑  收藏  举报