[BZOJ5297][Cqoi2018]社交网络(Matrix-Tree 矩阵-树定理)

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=5297

Solution

矩阵树定理的拓展——外向树生成树计数。
基尔霍夫矩阵 C 入度矩阵减去邻接矩阵。
辅助矩阵两个: B ( n × m ) D ( m × n )
对于第 i 条有向边 < u , v > B [ u , i ] = 1 , B [ v , i ] = D [ i , v ] 1 B D 其他位置为 0
同样 B D 等于基尔霍夫矩阵。
利用 Binet-Cauthy 定理将 矩阵乘积的行列式展开,就得到:

| C 1 , 1 | = | S | = n 1 | C 1 , 1 ( S ) |

C ( S ) 为边集 S 构成的基尔霍夫矩阵。
易得 | C 1 , 1 ( S ) | 表示选出的 n 1 条边是否构成外向树,构成外向树则为 1 ,否则为 0
题目要求取模,用逆元处理即可。
丢个链接:
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;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/81458184