[HNOI2011]XOR和路径 概率期望 高斯消元
题解:因为异或不太好处理,,,因此按位来算,这样最后的答案就是每一位上的值乘对应的权值再求和。本着期望要倒退的原则,,,我们设$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 }