解析
不难想到第一步利用期望线性性逐位考虑。
然后就变成求一个布尔变量的期望了,可以直接转化为求概率。
我一开始的想求从1出发异或和为0/1的概率,然而这个东西在原点1附近的转移特别别扭…老出现概率大于1的迷惑情况。
然后我就不会了
正解是反过来想,设 fxf_xfx 为从 xxx 出发到 nnn 的路径异或和为1的概率,然后像类似游走的方法转移就行了。
为什么要这样?
首先,本题的图必然联通,此时,从一个点 xxx 必然可以走到 nnn,但从 111 不一定能走到 xxx。
比如说 1-3-2 这样的图中,1就是走不到2的。
那么在题解的定义中,1−fx1-f_x1−fx 就使 x−>nx->nx−>n 的路径异或和为 000 的概率,而在我的定义中,1−fx1-f_x1−fx 则是 111 走不到 xxx 和 1−>x1->x1−>x 路径异或和为0的概率和。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define OK debug("OK\n")
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
const int N=100+20;
const int mod=1e9+7;
int n,m;
struct node{int to,nxt,w;
}p[N*N<<1];
int fi[N],cnt;
inline void addline(int x,int y,int w){p[++cnt]=(node){y,fi[x],w};fi[x]=cnt;
}
int mi[40],o=30;
double a[N][N],ans,f[N];
int d[N];
void gauss(){for(int i=1;i<=n;i++){int id=i;for(int j=i+1;j<=n;j++) if(abs(a[j][i])>abs(a[id][i])) id=j;if(id!=i) swap(a[id],a[i]);for(int j=i+1;j<=n;j++){for(int k=i+1;k<=n+1;k++) a[j][k]-=a[j][i]/a[i][i]*a[i][k];}}for(int i=n;i>=1;i--){f[i]=a[i][n+1]/a[i][i];for(int j=1;j<i;j++) a[j][n+1]-=a[j][i]*f[i];}return;
}
void work(int k){memset(a,0,sizeof(a));for(int i=1;i<=n;i++){a[i][i]=1;if(i==n) continue;for(int o=fi[i];~o;o=p[o].nxt){int j=p[o].to;int op=(p[o].w&mi[k])?1:0;if(op){a[i][n+1]+=1.0/d[i];a[i][j]+=1.0/d[i];}else{a[i][j]+=-1.0/d[i];}}}//for(int i=1;i<=n;i++){//for(int j=1;j<=n+1;j++) printf("%.2lf ",a[i][j]);//puts("");//}gauss();ans+=mi[k]*f[1];
//printf("k=%d f=%lf\n",k,f[1]);
}signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifmemset(fi,-1,sizeof(fi));cnt=-1;mi[0]=1;for(int i=1;i<=o;i++) mi[i]=mi[i-1]<<1;n=read();m=read();for(int i=1;i<=m;i++){int x=read(),y=read(),w=read();d[x]++;addline(x,y,w);if(x^y) d[y]++,addline(y,x,w);}for(int i=0;i<=o;i++) work(i);printf("%.3lf\n",ans);
}
/*
*/