【2020杭电多校】第六场 Expectation 矩阵树定理

Expectation

题意

给出一个 n 个点,m 条边的无向图,现在随机选择一颗生成树,一颗生成树的价值为边权的 & 和。

问生成树价值的期望是多少?

思路

​ 按位考虑,枚举所有边,如果当前边权的二进制的第 i 位为 1 ,把这条边放到图中,然后使用矩阵树定理求生成树的数量。

​ 答案(rel = sum_{i=0}^{31}num_i*(1<<i)*sum^{-1}),sum表示整个图的生成树数量,(num_i)表示枚举第 i 位时生成树的数量

代码

#include <bits/stdc++.h>
#define fuck system("pause")
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const double eps = 1e-6;
const ll inf = 0x3f3f3f3f;
const ll N = 2e5 + 10;

ll mat[110][110];
struct Edge{
    ll u, v, w;
} edge[N];

ll gauss(ll n){
    ll ans = 1;
    for (ll i = 1; i < n;i++){
        for (ll j = i + 1; j < n; j++) {
            while(mat[j][i]){
                ll t = mat[i][i] / mat[j][i];
                for (ll k = i; k < n;k++){
                    mat[i][k] = (mat[i][k] - t * mat[j][k] + mod) % mod;
                }
                swap(mat[i], mat[j]);
                ans = -ans;
            }
        }
        ans = (ans * mat[i][i]) % mod;
    }
    return (ans + mod) % mod;
}

ll qpow(ll a, ll b)
{
    ll ans = 1;
    a %= mod;
    while (b) {
        if (b & 1) {
            ans = (ans * a) % mod;
        }
        b >>= 1;
        a = a * a % mod;
    }
    return ans % mod;
}

int main(){
    ll T;
    scanf("%lld", &T);
    while(T--){
        ll n,m;
        scanf("%lld%lld", &n, &m);
        memset(mat, 0, sizeof(mat));
        for (ll i = 1; i <= m;i++){
            scanf("%lld%lld%lld", &edge[i].u, &edge[i].v, &edge[i].w);
        }
        ll ans = 0;
        for (ll i = 0; i < 32;i++){
            memset(mat, 0, sizeof(mat));
            for (ll j = 1; j <= m;j++){
                if(edge[j].w&(1<<i)){
                    ll u = edge[j].u, v = edge[j].v;
                    mat[u][u]++, mat[v][v]++;
                    mat[u][v]--, mat[v][u]--;
                }
            }
            ll num = gauss(n);
            ans = (ans + (1 << i) * num % mod) % mod;
        }
        memset(mat, 0, sizeof(mat));
        for(ll i=1;i<=m;i++){
            ll u = edge[i].u, v = edge[i].v;
            mat[u][u]++, mat[v][v]++;
            mat[u][v]--, mat[v][u]--;
        }
        printf("%lld
", ans * qpow(gauss(n), mod - 2) % mod);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/valk3/p/13456676.html