2020杭电多校第六场 hdu6836 Expectation

睡不着 , 水发题解吧

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=6836

题目大意

给定 N 个点 M 条边的无相连通图

定义图的生成树的值为该生成树所有边权按位与的值

问这张图的生成树的期望值是多少

解题思路 

定义原图的生成树的个数为 SUM

因为要进行位运算 , 所以往二进制的角度思考

我们将每条边的边权转换为二进制数

那么答案的二进制数第 i 位的期望值会是多少呢

很显然只有当生成树的每条边的第 i 位都为 1 时才会对答案产生贡献 ( &运算 )

于是我们可以将第 i 位为 1 的边取出来重新建图

并且计算新建的图的生成树的个数 , 记为 NOW

那么答案的二进制数第 i 位的期望值就为 $\dfrac{now}{sum}\times ( 1 < < i) $

简单模拟一下即可 ( 生成树的个数用 Matrix Tree 计算)

AC_Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e2 + 10 , mod = 998244353;
const double eps = 1e-12;
int G[N][N];
int n , m;
int pow_mod(int x , int n , int mod)
{
    int res = 1;
    while(n)
    {
        if(n & 1) res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res;
}
int dcmp(int x)
{
    if(x <= eps || x >= -eps) return 0;
    else return x < 0 ? -1 : 1;
}
int Gauss(int n)
{
    int ans = 1;
    for(int i = 1 ; i < n ; i ++)
    {
        for(int k = i + 1 ; k < n ; k ++)
        {
            while(G[k][i])
            {
                int d = G[i][i] / G[k][i];
                for(int j = i ; j < n ; j ++) G[i][j] = (G[i][j] - 1LL * d * G[k][j] % mod + mod) % mod;
                swap(G[i] , G[k]) , ans = -ans;
            }
        }
        ans = 1LL * ans * G[i][i] % mod , ans = (ans + mod) % mod;
    }
    return ans;
}
void init(int n)
{
    memset(G , 0 , sizeof(G));
}
vector<pair<int , int>>vec[50];
signed main()
{
    ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
    int T = 1;
    cin >> T;
    while(T --)
    {
        for(int i = 0 ; i <= 32 ; i ++) vec[i].clear();
        cin >> n >> m;
        for(int i = 1 ; i <= m ; i ++)
        {
            int x , y , w;
            cin >> x >> y >> w;
            G[x][x] ++ , G[y][y] ++;
            G[x][y] -- , G[y][x] --;
            for(int j = 32 ; ~j ; j --) if((w >> j) & 1) vec[j].push_back(make_pair(x , y));
        }
        int tot = Gauss(n) , ans = 0;
        int p = pow_mod(tot , mod - 2 , mod);
        for(int j = 0 ; j <= 32 ; j ++)
        {
            init(n);
            for(auto i : vec[j])
            {
                int x = i.first , y = i.second;
                G[x][x]++;
                G[y][y]++;
                G[x][y]--;
                G[y][x]--;
            }
            int now = Gauss(n);
            ans += ((1ll << j) % mod) * now % mod * p;
            ans %= mod;
        }
        cout << ans << '\n';
    }
    return 0;
}
posted @ 2020-08-07 07:29  GsjzTle  阅读(283)  评论(0编辑  收藏  举报