bzoj 2337 [HNOI2011]XOR和路徑 高斯消元+期望dp
阿新 • • 發佈:2018-08-14
return set 時間復雜度 += memset als \n line sum
題面
題目傳送門
解法
既然有異或,那麽我們把每一位單獨考慮一下
先枚舉是二進制的第幾位,然後設\(f_i\)表示點\(i\)這一位為1的概率是多少
顯然,可以列出一個方程
註意,自環的出度不能被計算2遍
高斯消元解這個方程即可
最後答案為\(\sum2^i×f_{1,i}\)
時間復雜度:\(O(30n^3)\)
代碼
#include <bits/stdc++.h> #define double long double #define eps 1e-9 #define N 110 using namespace std; struct Edge { int next, num, v; } e[N * N * 16]; int cnt, s[N]; double a[N][N]; void add(int x, int y, int v) { e[++cnt] = (Edge) {e[x].next, y, v}; e[x].next = cnt; } void gauss(int n) { for (int i = 1; i <= n; i++) { if (fabs(a[i][i]) <= eps) for (int j = i + 1; j <= n; j++) if (fabs(a[j][i]) > eps) for (int k = 1; k <= n + 1; k++) swap(a[i][k], a[j][k]); for (int j = i + 1; j <= n + 1; j++) a[i][j] /= a[i][i]; for (int j = 1; j <= n; j++) { if (i == j) continue; for (int k = i + 1; k <= n + 1; k++) a[j][k] -= a[j][i] * a[i][k]; } } } int main() { ios::sync_with_stdio(false); int n, m; cin >> n >> m; cnt = n; for (int i = 1; i <= m; i++) { int x, y, v; cin >> x >> y >> v; if (x == y) s[x]++, add(x, y, v); else s[x]++, s[y]++, add(x, y, v), add(y, x, v); } double ans = 0; for (int l = 0; l <= 30; l++) { memset(a, 0, sizeof(a)); for (int i = 1; i < n; i++) { a[i][i] = 1; for (int p = e[i].next; p; p = e[p].next) { int k = e[p].num, v = e[p].v; if (((v >> l) & 1) == 1) { a[i][k] += 1.0 / s[i]; if (k != n) a[i][n] += 1.0 / s[i]; } else if (k != n) a[i][k] -= 1.0 / s[i]; } } gauss(n - 1); ans += (1 << l) * a[1][n]; } cout << fixed << setprecision(3) << ans << "\n"; return 0; }
bzoj 2337 [HNOI2011]XOR和路徑 高斯消元+期望dp