zoukankan      html  css  js  c++  java
  • 矩阵树 [2020 Multi-University Training Contest 6 Expectation]

    矩阵树 2020 Multi-University Training Contest 6 Expectation

    题目大意:

    给你一张n个点m条边的图,定义一个最小生成树的权值是所有边相与的结果,现在你随机选一个最小生成树,计算期望的权值,答案对998244353取模。

    题解:

    分析题目:

    • 这个期望等于概率乘以权值,每一张图出现的概率可以算出来,所以现在只要求所有可能的权值之和即可。
    • 求一张图所有最小生成树,一般用矩阵树来写,所以考虑怎么建树,达到题目的要求。
    • 这个题目要求最小生成树的权值相与,那么可以考虑把权值拆开成二进制,1e9,最多32位,所以对于每一位,答案就是最小生成树的个数乘以一个(2^x)
    #include <bits/stdc++.h>
    #define debug(x) cout<<"debug:"<<#x<<" = "<<x<<endl;
    using namespace std;
    typedef long long ll;
    const int maxn = 110;
    const int mod = 998244353;
    ll K[maxn][maxn];
    ll Gauss(int n){//求矩阵K的n-1阶顺序主子式
        ll res=1;
        for(int i=1;i<=n-1;i++){//枚举主对角线上第i个元素
            for(int j=i+1;j<=n-1;j++){//枚举剩下的行
                while(K[j][i]){//辗转相除
                    ll t=K[i][i]/K[j][i];
                    for(int k=i;k<=n-1;k++)//转为倒三角
                        K[i][k]=(K[i][k]-t*K[j][k]+mod)%mod;
                    swap(K[i],K[j]);//交换i、j两行
                    res=-res;//取负
                }
            }
            res=(res*K[i][i])%mod;
        }
        return (res+mod)%mod;
    }
    struct node{
        int u,v;
        int bit[40];
    }e[10010];
    
    ll p[40];
    void init() {
        p[0] = 1;
        for (int i = 1; i < 40; i++) p[i] = p[i - 1] * 2 % mod;
    }
    long long inv(long long x,long long mod) {
        x %= mod;
        long long k = mod - 2, ans = 1;
        while (k) {
            if (k & 1) ans = ans * x % mod;
            x = x * x % mod;
            k >>= 1;
        }
        return ans;
    }
    int main() {
        int T;
        init();
        scanf("%d", &T);
        while (T--) {
            int n, m;
            scanf("%d%d", &n, &m);
            memset(K, 0, sizeof(K));
            for (int i = 1; i <= m; i++) {
                int u, v, w;
                scanf("%d%d%d", &u, &v, &w);
                e[i].u = u, e[i].v = v;
                K[u][u]++, K[v][v]++;
                K[u][v]--, K[v][u]--;
                for (ll j = 32; j >= 0; j--) {
                    int x = (1ll << j) & w;
                    e[i].bit[j] = x;
                }
            }
            ll ans = 0;
            ll num = inv(Gauss(n), mod);
            for (ll i = 0; i <= 32; i++) {
                memset(K, 0, sizeof(K));
                for (int j = 1; j <= m; j++) {
                    if (e[j].bit[i] == 0) continue;
                    int u = e[j].u, v = e[j].v;
                    if (u == v) continue;
                    K[u][u]++, K[v][v]++;
                    K[u][v]--, K[v][u]--;
                }
                ans = (ans + Gauss(n) * p[i] % mod) % mod;
            }
            ans = ans * num % mod;
            printf("%lld
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    思科交换机端口安全配置
    华为交换机端口安全配置
    多行文本出现省略号必备的条件(面试题)
    单行文本出现省略号必备的条件(面试题)
    让多个元素在一行显示的方法和技巧(面试题)
    overflow的多个作用
    雪碧图的使用和制作技巧
    列举background属性的8个属性值(面试题)
    background-origin设置背景图像的参考原点(位置)
    background-clip设置对象的背景图像向外裁剪的区域
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13454944.html
Copyright © 2011-2022 走看看