• 【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;
    }
    

  • 相关阅读:
    android项目启动应用,卸载应用,分享
    android项目复杂的listview
    android项目获得手机里所有的应用程序
    android项目获取指定目录下可用空间
    android项目实现电话自动挂断的功能
    android项目浮窗的移动
    android项目双击或者多击的实现
    C#设计模式之工厂方法与简单工厂
    C#二分查找法与拉格朗日查找法
    C#快速排序算法
  • 原文地址:https://www.cnblogs.com/valk3/p/13456676.html
Copyright © 2020-2023  润新知