#高斯消元,概率期望,动态规划#洛谷 3211 [HNOI2011]XOR和路径 分析 代码

题目


由于不同二进制位互不影响,所以考虑按位处理
(dp[i])表示第(i)个点某一位为1的概率,那么

[dp[i]=frac{1}{deg[i]}(sum_{(i,u)=0}dp[u]+sum_{(i,v)=1}(1-dp[v])) ]

那么

[deg[i]dp[i]+sum_{(i,v)=1}dp[v]-sum_{(i,u)=0}dp[u]=sum_{(i,v)=1}1 ]

就可以用高斯消元处理啦,最后对于每一位答案乘上(2^i),注意自环不用加反向边


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
#include <algorithm>
#define rr register
using namespace std;
const int N=111; double ans,a[N][N];
struct node{int y,w,next;}e[20011];
int n,k=1,deg[N],ls[N],W;
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void add(int x,int y,int w){e[++k]=(node){y,w,ls[x]},ls[x]=k;}
inline void Gauss(int n){
    for (rr int i=1;i<=n;++i){
    	rr int p=i;
    	for (rr int j=i+1;j<=n;++j)
    	if (fabs(a[j][i])>fabs(a[p][i])) p=j;
    	if (p!=i) for (rr int j=1;j<=n+1;++j) swap(a[i][j],a[p][j]);
    	for (rr int j=n+1;j>=i;--j) a[i][j]/=a[i][i];
    	for (rr int j=1;j<=n;++j)
		if (i!=j){
    		rr double elim=a[j][i]/a[i][i];
    		for (rr int k=i;k<=n+1;++k)
    		    a[j][k]-=elim*a[i][k];
		}
	}
}
inline void build(int S){
	memset(a,0,sizeof(a)),a[n][n]=1;
	for (rr int i=1;i<n;++i){
		a[i][i]=deg[i];
		for (rr int j=ls[i];j;j=e[j].next)
		if (e[j].w&S) ++a[i][e[j].y],++a[i][n+1];
		    else --a[i][e[j].y];
	}
}
signed main(){
    n=iut();
    for (rr int m=iut();m;--m){
    	rr int x=iut(),y=iut(),w=iut();
    	add(x,y,w),++deg[x],W=W>w?W:w;
    	if (x^y) add(y,x,w),++deg[y];
	}
	for (rr int S=1;S<=W;S<<=1)
	    build(S),Gauss(n),ans+=a[1][n+1]*S;
    return !printf("%.3lf
",ans);
}