[HEOI2015]小 Z 的房间(矩阵树定理&高斯消元辗转相除法)

[HEOI2015]小 Z 的房间(luogu)

Solution

关于矩阵树定理

这道题要求整数,而且要取模

根据上面那篇文章中最后一条性质——如果把矩阵的某一行(列)加上另一行(列)的k倍,则行列式的值不变。

我们可以使用辗转相除法

将 gcd 求法中 a%b 改为 a-b*(a/b)

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define ll long long
using namespace std;
const int N=100;
ll a[N][N],P=1e9;
int n,m,id[N][N],cnt;
char s[N][N];
void add(int u,int v)
{
    a[u][u]++,a[v][v]++,a[u][v]--,a[v][u]--;
}
void solve(int n)
{
    ll ans=1;
    for(int i=1;i<=n;i++)
    {
        for(int k=i+1;k<=n;k++)
            while(a[k][i])
            {
                ll rate=a[i][i]/a[k][i];
                for(int j=1;j<=n;j++) a[i][j]=(a[i][j]-rate*a[k][j]%P+P)%P;
                swap(a[i],a[k]),ans=-ans;
            }
        ans=ans*a[i][i]%P;
    }
    printf("%lld\n",(ans+P)%P);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s[i]+1);
        for(int j=1;j<=m;j++)
            if(s[i][j]=='.') id[i][j]=++cnt;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]!='.') continue;
            if(id[i+1][j]) add(id[i][j],id[i+1][j]);
            if(id[i][j+1]) add(id[i][j],id[i][j+1]);
        }
    solve(cnt-1);
    return 0;
}

 

猜你喜欢

转载自www.cnblogs.com/hsez-cyx/p/12521921.html
今日推荐