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; }
标签:杭电多校,第六场,hdu6836,return,int,++,ans,--,mod 来源: https://www.cnblogs.com/StarRoadTang/p/13450197.html