https://www.lydsy.com/JudgeOnline/problem.php?id=2337
概率期望dp
若直接求期望,和与异或的运算不好转换
于是考虑枚举位数,$f_i$表示改位为从点$i$出发走到点$n$,该位为1的概率
转移还是很简单的
注意概率期望dp很多都要倒着推,一开始顺着推居然水过了样例,然后一提交就全WA
#include<bits/stdc++.h> using namespace std; const int N=105,M=1e4+5; double eps=1e-5; int n,m; int deg[N],head[N],ver[M<<1],nxt[M<<1],val[M<<1],ce; double mat[N][N],f[N],ans; void Gauss(int now) { //cout<<now<<endl; if(abs(mat[now][now])<eps) { for(int i=now+1;i<n;++i) if(abs(mat[i][now])>=eps) { for(int j=1;j<=n+1;++j) swap(mat[i][j],mat[now][j]); break; } } if(abs(mat[now][now])>=eps) { for(int i=now+1;i<n;++i) { double tmp=mat[i][now]/mat[now][now]; for(int j=1;j<=n+1;++j) mat[i][j]-=mat[now][j]*tmp; } } if(now<n) Gauss(now+1); if(now==n) f[now]=0; else f[now]=mat[now][n+1]/mat[now][now]; for(int i=now-1;i>=1;--i) mat[i][n+1]-=mat[i][now]*f[now]; } void adde(int a,int b,int c) { ver[++ce]=b,val[ce]=c,nxt[ce]=head[a],head[a]=ce; } int main() { //freopen("1.in","r",stdin); freopen("1.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) { int u,v,w; scanf("%d%d%d",&u,&v,&w); adde(u,v,w); if(v!=u) adde(v,u,w); ++deg[v]; if(v!=u) ++deg[u]; } for(int s=0;s<=30;++s) { for(int i=1;i<=n+1;++i) for(int j=1;j<=n+1;++j) mat[i][j]=0; for(int i=1;i<n;++i) { mat[i][i]=-1.0; for(int j=head[i];j;j=nxt[j]) { int y=ver[j]; if((val[j]&(1<<s))) mat[i][y]-=1.0/(double)deg[i],mat[i][n+1]-=1.0/(double)deg[i]; else mat[i][y]+=1.0/(double)deg[i]; } } /* for(int i=1;i<=n;++i) { for(int j=1;j<=n+1;++j)printf("%.3lf ",mat[i][j]); cout<<endl; }*/ Gauss(1); //cout<<f[1]<<endl; ans+=f[1]*(double)(1<<s); } printf("%.3lf\n",ans); return 0; }