Address
https://www.lydsy.com/JudgeOnline/problem.php?id=5297
Solution
矩阵树定理的拓展——外向树生成树计数。
基尔霍夫矩阵
C
C
为入度矩阵减去邻接矩阵。
辅助矩阵两个: ,
D(m×n)
D
(
m
×
n
)
。
对于第
i
i
条有向边 ,
B[u,i]=1,B[v,i]=D[i,v]−1
B
[
u
,
i
]
=
1
,
B
[
v
,
i
]
=
D
[
i
,
v
]
−
1
。
B
B
和 其他位置为
0
0
。
同样 等于基尔霍夫矩阵。
利用 Binet-Cauthy 定理将 矩阵乘积的行列式展开,就得到:
C(S) C ( S ) 为边集 S S 构成的基尔霍夫矩阵。
易得 表示选出的 n−1 n − 1 条边是否构成外向树,构成外向树则为 1 1 ,否则为 。
题目要求取模,用逆元处理即可。
丢个链接:
https://blog.csdn.net/xyz32768/article/details/81413569
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 255, PYZ = 10007;
int n, m, a[N][N], inv[PYZ];
int gauss() {
int i, j, k, ans = 1, ok = 0; For (i, 2, n) {
int id = -1; For (j, i, n) if (a[j][i]) {id = j; break;}
if (id == -1) return 0; if (id != i) {
For (j, 2, n) swap(a[i][j], a[id][j]); ok ^= 1;
}
For (j, i + 1, n) {
int kd = 1ll * inv[a[i][i]] * a[j][i] % PYZ;
For (k, 2, n) a[j][k] =
(a[j][k] - 1ll * a[i][k] * kd % PYZ + PYZ) % PYZ;
}
ans = 1ll * ans * a[i][i] % PYZ;
}
return ok ? (PYZ - ans) % PYZ : ans;
}
int main() {
int i, j, x, y; n = read(); m = read();
while (m--) y = read(), x = read(), a[x][y] = (a[x][y] + PYZ - 1) % PYZ,
a[y][y]++; inv[1] = 1; For (i, 2, PYZ - 1)
inv[i] = 1ll * (PYZ - PYZ / i) * inv[PYZ % i] % PYZ;
cout << gauss() << endl; return 0;
}