带模数的基尔霍夫矩阵树求生成树个数

HDU多校第六场1010
Expectation
Problem Description
You are given an undirected graph consisting of n vertices with m weighted edges. We define the weight of a spanning tree as the bitwise AND of all edges’ weight in spanning tree.

Now select a spanning tree randomly, you should calculate the expected value of the weight of this spanning tree. You are required to print the result mod 998244353. i.e., print x×y−1 mod 998244353 where x×y−1 is the irreducible fraction representation of the result, where y−1 denotes the multiplicative inverse of y modulo 998244353.

Input
The first line is an integer t(1≤t≤10), the number of test cases.

For each test case, there are two space-separated integers n(2≤n≤100) and m(1≤m≤104) in the first line, the number of nodes and the number of edges.

Then follows m lines, each contains three integers u,v,w(1≤u,v,≤n,1≤w≤109,u≠v), space separated, denoting an weight edge between u and v has weight w.

Output
For each test case, output a single line with a single integer, denoting the answer.

Sample Input
1
3 3
1 2 1
1 3 1
2 3 1

Sample Output
1

#include
using namespace std;

const int N=110;

typedef long long LL;

const LL mod = 998244353;

LL ksm(LL a, LL b){
    LL s = 1;
    while(b){
        if(b & 1) s = s * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return s;
}

int degree[N];
LL C[N][N];

LL det(LL a[][N],int n)//生成树计数:Matrix-Tree定理
{
    LL ret=1;
    int sign = 0;
    for(int i=1; i<n; i++)
    {
        for(int j=i+1; j<n; j++)
            while(a[j][i])
            {
//                LL t=a[i][i]/a[j][i];
                LL t = a[i][i] * ksm(a[j][i], mod - 2) % mod;
                for(int k=i; k<n; k++)
                    a[i][k]=(a[i][k]-a[j][k]*t)%mod;
                for(int k=i; k<n; k++)
                    swap(a[i][k],a[j][k]);
                sign ^= 1;
            }
        if(a[i][i]==0) return 0;
        ret=ret*a[i][i]%mod;
    }
    if(sign) ret *= -1; 
    if(ret<0) ret += mod;
    return ret;
}
int u[10010], v[10010], w[10010];
int main()
{
    int tcase;
    scanf("%d",&tcase);
    while(tcase--)
    {

        int n, m;
        scanf("%d%d", &n, &m);
        memset(C, 0, sizeof C);
        memset(degree, 0, sizeof degree);
        for(int i = 1; i <= m; i++){
            scanf("%d%d%d", &u[i], &v[i], &w[i]);
            u[i]--;
            v[i]--;
            C[u[i]][v[i]]--;
            C[v[i]][u[i]]--;
            degree[u[i]]++;
            degree[v[i]]++;
        }
        for(int i = 0; i < n; i++) C[i][i] = degree[i];
        LL tot = det(C, n), ans = 0;
        for(LL val = 1; val <= 1000000000; val <<= 1){
            memset(C, 0, sizeof C);
            memset(degree, 0, sizeof degree);
            for(int i = 1; i <= m; i++){
                if(val & w[i]){
                    C[u[i]][v[i]]--;
                    C[v[i]][u[i]]--;
                    degree[u[i]]++;
                    degree[v[i]]++;
                }
            }
            for(int i = 0; i < n; i++) C[i][i] = degree[i];
            ans = (ans + det(C, n) * val) % mod;
        }
        ans = ans * ksm(tot, mod - 2) % mod;
        if(ans < 0) ans += mod;
        printf("%lld\n", ans);
    }
    return 0;
}

你可能感兴趣的:(带模数的基尔霍夫矩阵树求生成树个数)