[JSC2021G] Spanning Tree 题解
复习了矩阵树定理,再来试试水。
考虑如何将原问题转换为生成树计数:首先
可以借助 AtCoder Library 中的 dsu 和 modint 实现。
放代码:
#include<bits/stdc++.h>
#include<atcoder/all>
#define int long long
using namespace std;
using namespace atcoder;
using mint=modint1000000007;
mint det(vector<vector<mint> > &a){
mint s=1,f=1;
for(int i=0;i<a.size()-1;i++)
for(int j=i+1;j<a.size()-1;j++){
while(a[i][i].val()){
mint d=a[j][i]/a[i][i];
for(int k=i;k<a.size()-1;k++)
a[j][k]-=a[i][k]*d;
swap(a[i],a[j]),f=-f;
}
swap(a[i],a[j]),f=-f;
}
for(int i=0;i<a.size()-1;i++)
s*=a[i][i];
return s*f;
} // 求行列式
main(){
ios::sync_with_stdio(false);
int n,c=0; cin>>n;
vector a(n,vector<int>(n));
for(auto &i:a)for(auto &j:i)cin>>j;
dsu d(n);
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
if(a[i][j]>0){
if(d.same(i,j))cout<<"0\n",exit(0);
else d.merge(i,j);
} // 并查集维护连通块
vector<int> m(n);
for(int i=0;i<n;i++)
if(i==d.leader(i))m[i]=c++;
vector f(c,vector<mint>(c));
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
if(a[i][j]<0&&!d.same(i,j)){
int x=m[d.leader(i)],y=m[d.leader(j)];
f[x][x]++,f[y][y]++,f[x][y]--,f[y][x]--;
} // 构造基尔霍夫矩阵
cout<<det(f).val()<<endl;
return 0;
}