1010 Expectation(期望,矩阵树定理)
题目大意
给一个无向连通图,任意从图中取出一个生成树(该图的所有生成树等概率被取到),求该生成树每条边权进行位运算AND后的期望值。
解题思路
位运算题目通用的思路,按位计算,累加贡献。我们可以只看每条边权的第i位,这样就可以把这个图的所有边权变成0和1(1表示原来边权在第i位上的值是1,0同理)。根据期望的线性性质: E ( X + Y ) = E ( X ) + E ( Y ) E(X + Y) = E(X) + E(Y) E(X+Y)=E(X)+E(Y)所求的期望值就等于每一位期望值乘上这一位对应的权值求和,即(设考虑第 i i i位时的期望值位 E i E_i Ei) E = ∑ E i ⋅ 2 i E = \sum E_i \cdot2^i E=∑Ei⋅2i
算法实现
求期望值
E
i
E_i
Ei要先求概率
P
i
P_i
Pi,也就是在这张由0,1边组成的图中,任意选出一个生成树,边权AND值为1的概率。显然根据AND的性质必须要求所选的生成树每条边都为1。这样就可以用所有1边组成的图的生成树的个数,除以原图的总的生成树个数来表示概率。期望就是概率乘上收益,及刚才算出的概率乘上1,即
E
i
=
P
i
⋅
1
+
(
1
−
P
i
)
⋅
0
=
P
i
E_i = P_i \cdot 1 + (1 - P_i)\cdot 0 = P_i
Ei=Pi⋅1+(1−Pi)⋅0=Pi
至于如何求无向图生成树的个数,可以用矩阵树定理来求。具体细节参考代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN = 2e2 + 5;
const int Mod = 998244353;
ll mpow(ll x, ll b) {
ll ret = 1ll;
for (; b; b >>= 1, x = x * x % Mod)
if (b & 1) ret = ret * x % Mod;
return ret;
}
// 求基尔霍夫矩阵A的行列式
ll determinant(int n, ll a[][MAXN]) {
char sign = 0;
ll ans = 1ll;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
int x = i, y = j;
// 利用类似gcd的迭代方式来消元
while (a[y][i]) {
ll t = a[x][i] / a[y][i];
for (int k = i; k <= n; k++)
a[x][k] = (a[x][k] - a[y][k] * t) % Mod;
swap(x, y);
}
// 最后a[i][i]等于0,a[x][i]不等于0,要把i行和x行交换。
if (x != i) {
for (int k = 1; k <= n; k++)
swap(a[i][k], a[x][k]);
sign ^= 1;
}
}
ans = ans * a[i][i] % Mod;
}
if (sign) ans = -ans;
if (ans < 0) ans += Mod;
return ans;
}
ll G[MAXN][MAXN][30], A[MAXN][MAXN];
int n, m;
int main() {
std::ios::sync_with_stdio(false);
cin.tie(NULL), cout.tie(NULL);
int T; cin >> T;
while (T--) {
cin >> n >> m;
memset(G, 0, sizeof(G));
memset(A, 0, sizeof(A));
for (int u, v, w, i = 1; i <= m; i++) {
cin >> u >> v >> w;
for (int i = 0; (1l << i) <= w; i++)
if (w & (1l << i)) G[u][v][i] = ++G[v][u][i];
A[u][v] = --A[v][u];
++A[u][u], ++A[v][v];
}
ll inv = mpow(determinant(n - 1, A), Mod - 2), ans = 0;
// 按位计算,累加贡献
for (int k = 0; (1l << k) <= 1e9; k++) {
memset(A, 0, sizeof(A));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (G[i][j][k]) A[i][j] = -G[i][j][k], A[i][i] += G[i][j][k];
ans = (ans + (1ll << k) * determinant(n - 1, A) % Mod * inv % Mod) % Mod;
}
cout << ans << endl;
}
return 0;
}