HDU 6836 Expectation (生成树计数+按位计算期望)

题意:给出一张无向图,求随机选择一个生成树的权值的期望。权值为mst的边权按位与后的结果。

题解:生成树计数+按位计算期望
总的生成树数量直接根据矩阵树定理求一下。

由于权值是按位与之后的结果,也就是说只有这颗mst所有权值的第 i 位都为1时才会有贡献,那我们单独考虑每一位的贡献。

遍历所有位,对于该位上为1的边连起来,然后跑生成树计数,该位的贡献就是2i * 数量。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
const int MOD = 998244353;
int t, n, m, u, v, w;
struct Matrix {
    
    
    int mat[110][110];
    void init() {
    
    
        memset(mat, 0, sizeof(mat));
    }
    int det(int n) {
    
    
        ll res = 1;
        for (int i = 1; i <= n; i++) {
    
    
            if (!mat[i][i]) {
    
     //若果对角线元素为0,把此行都一都移到下一行去
                bool flag = false;
                for (int j = i + 1; j <= n; j++) {
    
     //从i+1行开始找i列中的第一个不为0的元素,与现在的行交换
                    if (mat[j][i]) {
    
    //找到了该列不为0的元素,
                        flag = 1; //标记,交换
                        for (int k = i; k <= n; k++) swap(mat[i][k], mat[j][k]);
                        res = -res;// 换行系数变为负数
                        break; //退出.
                    }
                }
                if (!flag) return 0; //这一行全部为0,行列式值为0
            }
            for (int j = i + 1; j <= n; j++) {
    
    
                while (mat[j][i]) {
    
     //从下面的行找一个不为0的元素与第i行进行消元
                    ll t = mat[i][i] / mat[j][i];
                    for (int k = i; k <= n; k++) {
    
    
                        mat[i][k] = (mat[i][k] - t * mat[j][k]) % MOD;
                        swap(mat[i][k], mat[j][k]);//消元后,把0的行换到下面来。
                    }
                    res = -res;
                }
            }
            res *= mat[i][i];//对角线元素相乘
            res %= MOD;
        }
        return (res + MOD) % MOD;
    }
}ma;
struct node {
    
    
    int u, v, w;
}edge[11111];
ll fastpow(ll base, ll n, ll mod) {
    
    
    ll ans = 1;
    while (n) {
    
    
        if (n & 1) ans *= base % mod, ans %= mod;
        base *= base, base %= mod;
        n >>= 1;
    }
    return ans % mod;
}
int main() {
    
    
	scanf("%d", &t);
	while (t--) {
    
    
        ma.init();
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= m; i++) {
    
    
			scanf("%d%d%d", &u, &v, &w);
            edge[i] = {
    
     u, v, w };
            ma.mat[u][u]++;
            ma.mat[v][v]++;
            ma.mat[u][v]--;
            ma.mat[v][u]--;
		}
        ll sum = ma.det(n - 1), ans = 0;
        for (int i = 0; i <= 30; i++) {
    
    
            ma.init();
            for (int j = 1; j <= m; j++) {
    
    
                if (edge[j].w & (1 << i)) {
    
    
                    u = edge[j].u;
                    v = edge[j].v;
                    ma.mat[u][u]++;
                    ma.mat[v][v]++;
                    ma.mat[u][v]--;
                    ma.mat[v][u]--;
                }
            }
            int temp = ma.det(n - 1);
            ans = (ans + 1ll * (1 << i) * temp % MOD) % MOD;
        }
        printf("%lld\n", ans * fastpow(sum, MOD - 2, MOD) % MOD);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43680965/article/details/107858663