zoukankan      html  css  js  c++  java
  • 2020杭电HDU-6836多校第六场Expectation(拆位矩阵树及其注意事项)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6836
    CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/107850424

    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≤10^4)) 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≤10^9,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

    题目大意:给你一个无向图,其中n个点,m条边,每个边的边权为(w_i),定义树的权为树的所有边的边权的按位与。现在我们随机选择该图的一个生成树,问其生成树的权期望是多少。

    emmm,一眼就是矩阵树。。。但中间的边权就真的卡的死死的。。。不会算,后来看题解才知道的。

    每一位的按位与过程都是独立的,那么我们对每一位建立一个其含该位的边的基尔霍夫矩阵,然后就可以得出在该位下可以得到多少个生成树,那么他对答案的贡献就是(ans*frac{2^i}{sum})其中(i)表示是第几位,(ans)表示的是在该位下的生成树个数,(sum)表示的是总的生成树的个数。

    然后就可以开始跑矩阵树了,只不过需要注意的是,矩阵树的的高斯消元和一般的高斯消元不太一样,他是从2开始的!!!(一般的是从1开始的,然后很多时候就会得到0)这里就被卡了挺久的。接下来需要注意的是,100个点,1W条边,就算是完全图也没有这么多条边,所以他一定会存在重边,那么我们用vector保存就好了。

    以下是AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int mac=200;
    const int mod=998244353;
    
    vector<int>mp[mac][mac];
    ll mat[mac][mac];
    int n,m;
    
    ll qpow(ll a,ll b)
    {
        ll ans=1; 
        while (b){
            if (b&1) ans=ans*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return ans;
    }
    
    ll guass()
    {
        ll ans=1;
        for (int i=2; i<=n; i++){
            for (int j=i+1; j<=n; j++)
                while (mat[j][i]){
                    ll p=mat[i][i]/mat[j][i];
                    for (int k=i; k<=n; k++)
                        mat[i][k]=(mat[i][k]-mat[j][k]*p%mod+mod)%mod;
                    swap(mat[i],mat[j]);
                    ans=-ans;
                }
            ans=ans*mat[i][i]%mod;
        }
        return (ans+mod)%mod;
    }
    
    int main(int argc, char const *argv[])
    {
        int t;
        scanf ("%d",&t);
        while (t--){
            scanf ("%d%d",&n,&m);
            for (int i=1; i<=m; i++){
                int u,v,w;
                scanf ("%d%d%d",&u,&v,&w);
                mp[u][v].push_back(w); mp[v][u].push_back(w);
                mat[u][v]--; mat[v][u]--;
                mat[u][u]++; mat[v][v]++;
            }
            ll ans=qpow(guass(),mod-2);
            ll fz=0;
            for (int wei=0; wei<=30; wei++){
                memset(mat,0,sizeof mat);
                for (int i=1; i<=n; i++)
                    for (int j=i+1; j<=n; j++){
                        for (auto x:mp[i][j]){
                            if (x&(1<<wei)){
                                mat[i][j]--; mat[j][i]--; 
                                mat[i][i]++; mat[j][j]++;
                            }
                        }
                    }
                fz=(fz+qpow(2,wei)*guass()%mod)%mod;
            }
            memset(mat,0,sizeof mat);
            for (int i=1; i<=n; i++)
                for (int j=1; j<=n; j++) mp[i][j].clear();
            printf("%lld
    ",ans*fz%mod);
        }
        return 0;
    }
    
    路漫漫兮
  • 相关阅读:
    代码片段:ASCII纯数字文本数据转二进制格式
    Caffe使用CMake编译:Could Not find Boost
    Cannot uninstall '***'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.
    Ubuntu 14.04避雷系列:升级python到最新2.x版本
    过程记录:安装原版windows7
    代码片段:Shell脚本实现重复执行和多进程
    代码片段:基于STL实现的读取纯数字文本文件
    E: GPG 错误:http://developer.download.nvidia.com Release: 下列签名无效: NODATA 1 NODATA 2
    软件项目管理复习题要
    html转义字符表
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13449312.html
Copyright © 2011-2022 走看看