题目大意:
按位处理,设 $f[i]$ 表示点 $i$ 到点 $n$ 的异或和是 $1$ 的期望,有
其中 $j$ 为与 $i$ 相邻的点,$k$ 为 $i$ 发出的边的数量,如果边 $(i,j)$ 的权值的当前位是 $0$,则 $p_j=f[j]$,否则 $p_j=1-f[j]$。
高斯消元。
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 105, M = 20005;
struct Edge {
int v, w;
} e[M];
double a[N][N], ans;
int d[N], head[N], nxt[M], tot, n, m;
void add_edge(int u, int v, int w) {
nxt[++tot] = head[u];
head[u] = tot;
e[tot] = (Edge){v, w};
}
void gauss(){
for(int i = 1; i <= n; ++i) { //消去第i个未知数
int mx = i;
while (!a[mx][i]) ++mx; //找到绝对值最大的一行(本题绝对值最大就是1)
if (mx != i) std::swap(a[i], a[mx]);
double mul = a[i][i];
for(int j = i; j <= n + 1; ++j) a[i][j] /= mul; //第i行整体除掉未知数i的系数
for(int k = 1; k <= n; ++k) //消去第k行中的未知数i
if (k != i && a[k][i]) {
mul = a[k][i];
for(int j = i; j <= n + 1; ++j)
a[k][j] -= mul * a[i][j]; //第k行整体减去第i行乘mul
}
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
++d[u], add_edge(u, v, w);
if (u != v) ++d[v], add_edge(v, u, w);
}
for (int i = 0; i < 30; ++i) {
memset(a, 0, sizeof a);
for (int u = 1; u < n; ++u) {
a[u][u] = 1;
for (int j = head[u]; j; j = nxt[j]) {
int v = e[j].v;
if (e[j].w & (1 << i))
a[u][v] += 1.0 / d[u], a[u][n+1] += 1.0 / d[u];
else a[u][v] -= 1.0 / d[u];
}
}
a[n][n] = 1;
gauss();
ans += a[1][n+1] * (1 << i);
}
printf("%.3lf\n", ans);
return 0;
}
时间复杂度 $O(30n^3)$