1. 程式人生 > >[HNOI2011]XOR和路徑 概率期望 高斯消元

[HNOI2011]XOR和路徑 概率期望 高斯消元

xor gist ace get swa == head 處理 std

題解:因為異或不太好處理,,,因此按位來算,這樣最後的答案就是每一位上的值乘對應的權值再求和。本著期望要倒退的原則,,,我們設$f[i]$表示從$i$到$n$,xor和為1的概率。
那麽觀察$xor$的規則:
1 xor 1 = 0
0 xor 1 = 1 ----> 當xor 1時,結果為1的概率 = 原本為0的概率
1 xor 0 = 1
0 xor 0 = 0 ----> 當xor 0時,結果為1的概率 = 原本為1的概率
因此我們有如下轉移:
$$f[x] = \frac{1}{d_{x}}(\sum_{val = 0, (x, y) \in E} f[y] + \sum_{val = 1, (x, y) \in E} (1 - f[y]))$$

$$d_{x} f[x] = \sum_{val = 0, (x, y) \in E} f[y] + \sum_{val = 1, (x, y) \in E} (1 - f[y])$$
$$d_{x} f[x] - \sum_{val = 0, (x, y) \in E} f[y] + \sum_{val = 1, (x, y) \in E} f[y] = \sum_{val = 1, (x, y) \in E} 1$$
於是我們可以發現我們一共有n個方程,n個元,於是高斯消元即可。註意$f[n] = 0$

技術分享圖片
  1 #include<bits/stdc++.h>
  2 using
namespace std; 3 #define R register int 4 #define AC 110 5 #define ac 31000 6 #define LL long long 7 8 const double eps = 1e-8; 9 int n, m, maxn; 10 double ans; 11 int d[AC], id[AC]; 12 int Head[AC], Next[ac], date[ac], len[ac], tot; 13 double f[AC][AC]; 14 15 inline int
read() 16 { 17 int x = 0;char c = getchar(); 18 while(c > 9 || c < 0) c = getchar(); 19 while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar(); 20 return x; 21 } 22 23 inline void add(int f, int w, int S) 24 { 25 date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot, len[tot] = S, ++ d[f]; 26 if(f != w) date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot, len[tot] = S, ++ d[w]; 27 }//如果是自環的話只能算一次 28 29 inline void upmax(int &a, int b){ 30 if(b > a) a = b; 31 } 32 33 void pre() 34 { 35 n = read(), m = read(), id[1] = 1; 36 for(R i = 1; i <= m; i ++) 37 { 38 int a = read(), b = read(), c = read(); 39 add(a, b, c), upmax(maxn, c); 40 } 41 for(R i = 2; i <= 31; i ++) id[i] = id[i - 1] << 1; 42 } 43 44 void check() 45 { 46 printf("\n"); 47 for(int i = 1; i <= n; i ++) 48 { 49 for(int j = 1; j <= n + 1; j ++) printf("%.2lf ", f[i][j]); 50 printf("\n"); 51 } 52 } 53 54 void gauss() 55 { 56 //check(); 57 for(R i = 1, r = 1; i <= n; i ++, r = i) 58 { 59 for(R j = i; j <= n; j ++) 60 if(fabs(f[j][i]) > eps) {r = j; break;} 61 if(fabs(f[r][i]) < eps) return ; 62 if(i != r) for(R j = 1; j <= n + 1; j ++) swap(f[i][j], f[r][j]); 63 for(R j = i + 1; j <= n + 1; j ++) f[i][j] /= f[i][i]; 64 for(R j = 1; j <= n; j ++) 65 { 66 if(i == j) continue;//是continue不是break啊。。。。 67 for(R k = i + 1; k <= n + 1; k ++) f[j][k] -= f[i][k] * f[j][i]; 68 } 69 } 70 } 71 72 void build(int lim) 73 { 74 memset(f, 0, sizeof(f));//先清空 75 for(R i = 1; i < n; i ++) 76 { 77 f[i][i] = d[i]; 78 for(R j = Head[i]; j; j = Next[j]) 79 { 80 int now = date[j]; 81 if(id[lim] & len[j]) ++ f[i][now], ++ f[i][n + 1]; 82 else -- f[i][now];//不能直接賦值,因為可能會涉及到自己,,於是本來就有系數,就是抵消一部分而不是覆蓋全部了 83 } 84 } 85 //for(R i = 1; i <= n + 1; i ++) f[n][i] = (i == n);//特判最後一個點 86 f[n][n] = 1; 87 } 88 89 void work() 90 { 91 LL tmp = 1; 92 for(R i = 1; id[i] <= maxn; i ++) 93 { 94 build(i), gauss(); 95 ans += f[1][n + 1] * tmp, tmp <<= 1; 96 // printf("!!!%.3lf\n", ans); 97 } 98 printf("%.3lf\n", ans); 99 } 100 101 int main() 102 { 103 // freopen("in.in", "r", stdin); 104 pre(); 105 work(); 106 // fclose(stdin); 107 return 0; 108 }
View Code

[HNOI2011]XOR和路徑 概率期望 高斯消元