[HNOI2011]XOR和路径
给出一个n个点无向联通图以及其m条正整数边权,每次可以从一个顶点等概率选择一条出边,进入下一个顶点,定义一条路径的长度为该路径的异或和,询问从节点1到n的路径长度的期望,\(N≤100,M≤100000\)。
解
异或和自然想到线性基这一有力工具,而样本空间无限,自然使用期望代无限状态的方法,再加之概率不固定,考虑倒推,而异或不满足加和,这对期望是致命的,于是考虑二进制拆分,对边权的第k为考虑,于是设\(E(x)\)为从x到终点n的路径该位为1的概率,y为x的出边,\(dis[x][y]\)为x,y连边的边权的第k为上的数字,于是我们会有
\[E(x)=\sum_{dis[x][y]==1}(1-E(y))+\sum_{dis[x][y]==0}E(y)
\]
于是我们可以的到一个异或方程组,利用高斯消元,解出其值,结果乘上\(2^k\),对于每一位这样处理,累加结果即可。
参考代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
#define db long double
#define exact 0.00000001
using namespace std;
struct base{
db base[101];
}A[101],*B[101];
struct point{
point*next;int to,len;
}*pt,*head[101];
int out[101],n;db ans;
il void link(int,int,int),
read(int&),insert(base&),eam();
template<class free>il free Abs(free);
int main(){
int m,i,j,k;
read(n),read(m);
while(m--){
read(i),read(j),read(k);
link(i,j,k),++out[j];
if(i!=j)link(j,i,k),++out[i];
}
for(i=0;i<=31;++i){
memset(A,0,sizeof(A)),memset(B,0,sizeof(B));
for(j=1;j<n;++j){
A[j].base[j]=out[j];
for(pt=head[j];pt!=NULL;pt=pt->next)
if(pt->len>>i&1)++A[j].base[pt->to],++A[j].base[0];
else --A[j].base[pt->to];insert(A[j]);
}A[n].base[n]=1,insert(A[n]);
ans+=(1<<i)*B[1]->base[0];
}printf("%.3Lf",ans);
return 0;
}
template<class free>
il free Abs(free x){
return x<0?-x:x;
}
il void insert(base &x){
ri int i,j;
for(i=n;i;--i)
if(Abs(x.base[i])>exact){
if(B[i]==NULL){
for(j=0;j<=i;++j)
x.base[j]/=x.base[i];
return (void)(B[i]=&x);
}
for(j=0;j<=i;++j)
x.base[j]-=B[i]->base[j]*x.base[i];
}
}
il void read(int &x){
x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}
il void link(int x,int y,int z){
pt=new point,pt->to=y,pt->len=z;
pt->next=head[x],head[x]=pt;
}