[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("
");
 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("
");
 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
", ans);
 97     }
 98     printf("%.3lf
", 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
原文地址:https://www.cnblogs.com/ww3113306/p/10202277.html