M
M
T
=
L
MM^T=L
MMT=L
即
d
e
t
(
L
0
)
det(L_0)
det(L0)就是生成树的数量。
模板
SPOJ HIGH
题意
有重边无向图中,求生成树的数量
#include <bits/stdc++.h>
#define debug(__x) cout<<#__x<<"="<<__x<<endl
#define endl '\n'
using namespace std;
using ll = long long;
ll L[15][15];
ll det(ll a[][15],int n){
ll ans = 1;
for(int i = 1; i <= n; i++){ // 计算行列式从1开始
for(int j = i + 1; j <= n; j++){
while(a[j][i] != 0){
ll u = a[i][i] / a[j][i]; // 逆元
for(int k = i; k <= n; k++){
ll t = a[i][k] - a[j][k]*u;
a[i][k] = a[j][k];
a[j][k] = t;
}
ans = -ans;
}
}
ans = ans*a[i][i];
}
return ans;
}
int main(){
int T;
cin.tie(0),cout.tie(0);
ios::sync_with_stdio(false);
cin>>T;
while(T--){
memset(L,0,sizeof(L));
int n,m;
cin>>n>>m;
for(int v,u,i=0;i<m;++i){
cin>>v>>u;
--L[v][u];
--L[u][v];
++L[v][v];
++L[u][u];
}
cout<<det(L,n-1)<<endl;
}
}
应用
HDU多校Expectation
题意
在有重边的无向图中,求生成树的边权相与和的期望。
思路
a
n
d
and
and运算对于每个二进制位独立,可以分开求解。对于某一个二进制位
i
i
i,只有当生成树所有边权为1时该树的贡献为
2
i
2^i
2i,否则无贡献。问题就转化为了求边权都为1的边构成的图的生成树数量。求出所有权值和除以总的生成树数量就是答案了。
#include<bits/stdc++.h>
#define endl '\n'
#define debug(_x) cout<<#_x<<"="<<_x<<endl;
using namespace std;
using ll = long long;
const ll MOD = 998244353;
const int maxn = 2e5+5;
ll qpow(ll a,int b){
ll ans=1;
while(b){
if(b&1) ans = ans * a % MOD;
a = a*a % MOD;
b >>= 1;
}
return ans;
}
ll det(ll a[][102],int n){ // 求行列式
ll ans = 1;
for(int i = 1; i <= n; i++){ // 计算行列式从1开始
for(int j = i + 1; j <= n; j++){
while(a[j][i] != 0){
ll u = a[i][i] / a[j][i]; // 逆元
for(int k = i; k <= n; k++){
ll t = ((a[i][k] - a[j][k]*u % MOD) + MOD)%MOD;
a[i][k] = a[j][k];
a[j][k] = t;
}
ans = -ans;
}
}
ans = ans*a[i][i]%MOD;
}
return (ans+MOD)%MOD;
}
struct Edge{
int u,v,w;
}e[10005];
int n,m;
ll L[102][102];
int main(){
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--){
cin>>n>>m;
memset(L,0,sizeof(L));
for(int i=0;i<m;++i){
cin>>e[i].u>>e[i].v>>e[i].w;
--L[e[i].u][e[i].v];
--L[e[i].v][e[i].u];
++L[e[i].u][e[i].u];
++L[e[i].v][e[i].v];
}
ll up=0,down=det(L,n-1);
for(int i=0;i<32;++i){
int an = (1<<i);
memset(L,0,sizeof(L));
for(int j=0;j<m;++j){
if(e[j].w&an){
--L[e[j].u][e[j].v];
--L[e[j].v][e[j].u];
++L[e[j].u][e[j].u];
++L[e[j].v][e[j].v];
}
}
ll tmp = det(L,n-1); // 去掉第n行第n列
up+=an*tmp%MOD;
up %= MOD;
}
debug(up);debug(down);
cout<<up*qpow(down,MOD-2)%MOD<<endl;
}
}