题目链接:https://www.luogu.com.cn/problem/P3211
题意很简单,每次等概率向任意一个与当前结点相连的结点走去,求从
1
1
1到
n
n
n的异或和期望
考虑
d
p
dp
dp,设
d
p
[
i
]
dp[i]
dp[i]为从结点
i
i
i到
n
n
n的异或和
则由条件期望公式:
E
(
d
p
[
u
]
)
=
1
k
∑
(
u
,
v
)
∈
e
d
g
e
E
(
d
p
[
v
]
)
x
o
r
W
(
u
,
v
)
E(dp[u])=\frac{1}{k}\sum_{(u,v)\in{edge}}E(dp[v])\; xor\;W(u,v)
E(dp[u])=k1(u,v)∈edge∑E(dp[v])xorW(u,v)
其中
k
k
k为
u
u
u点度数
后效性很好考虑,高斯消元即可
但是式子中有异或怎么办?
再看看数据范围
n
=
100
n=100
n=100,想到可以进行二进制拆分(位运算常见搞法,因为期望是线性的),考虑每一位对答案的贡献,设
f
(
u
,
i
)
为
f(u,i)为
f(u,i)为
E
(
d
p
[
u
]
)
E(dp[u])
E(dp[u])第
j
j
j位
则:
E
(
d
p
[
u
]
)
=
∑
i
f
(
u
,
i
)
E(dp[u])=\sum _{i}{f(u,i)}
E(dp[u])=i∑f(u,i)
而:
f
(
u
,
i
)
=
1
k
(
∑
W
(
u
,
v
)
=
0
f
(
v
,
i
)
+
∑
W
(
u
,
v
)
=
1
1
−
f
(
v
,
i
)
)
f(u,i)=\frac{1}{k}(\sum_{W(u,v)=0}f(v,i)+\sum_{W(u,v)=1}{1-f(v,i)})
f(u,i)=k1(W(u,v)=0∑f(v,i)+W(u,v)=1∑1−f(v,i))
化简得:
k
∗
f
(
u
,
i
)
−
∑
W
(
u
,
v
)
=
0
f
(
v
,
i
)
+
∑
W
(
u
,
v
)
=
1
f
(
v
,
i
)
=
∑
w
(
u
,
v
)
=
1
1
k*f(u,i)-\sum_{W(u,v)=0}f(v,i)+\sum_{W(u,v)=1}f(v,i)=\sum_{w(u,v)=1}1
k∗f(u,i)−W(u,v)=0∑f(v,i)+W(u,v)=1∑f(v,i)=w(u,v)=1∑1
对于任意结点
u
u
u,就可以通过高斯消元求出
E
(
d
p
[
u
]
)
E(dp[u])
E(dp[u])
答案就是
E
(
d
p
[
1
]
)
E(dp[1])
E(dp[1])
注意:
E
(
d
p
[
n
]
)
=
0
E(dp[n])=0
E(dp[n])=0
C o d e Code Code
#include <bits/stdc++.h>
using namespace std;
inline int read();
const int MAXM=1e4,MAXN=100;
struct w{
int to,nx,val;
}head[MAXM+MAXM+10];
int a[MAXN+10],tot=0,d[MAXN+10];
double g[MAXN+10][MAXN+10];
inline void add(int,int,int,int);
void make_Matrix(int,int);
int Guess(int);
int main(){
//freopen ("std.in","r",stdin);
//freopen ("std.out","w",stdout);
int n,m;
n=read(),m=read();
for (register int i=1;i<=m;++i){
int x=read(),y=read(),val=read();
++d[x],++d[y];
add(x,y,++tot,val);
if (x!=y) add(y,x,++tot,val);
else --d[x];
}
double ans=0;
for (register int i=0;i<=30;++i){
make_Matrix(i,n);
if (Guess(n)==-1) break;
ans+=g[1][n+1]*(1<<i);
}
printf("%.3f\n",ans);
return 0;
}
inline int read(){
int x=0;
char c=getchar();
while (!isdigit(c))c=getchar();
while (isdigit(c))x=(x<<1)+(x<<3)+(c&15),c=getchar();
return x;
}
inline void add(int x,int y,int i,int val){head[i].to=y;head[i].nx=a[x];head[i].val=val;a[x]=i;}
void make_Matrix(int x,int n){
memset(g,0,sizeof(g));
for (register int i=1;i<n;++i){
g[i][i]=d[i];
for (register int j=a[i];j;j=head[j].nx){
int k=head[j].to;
if (head[j].val&(1<<x)) ++g[i][k],++g[i][n+1];
else --g[i][k];
}
}
g[n][n]=1;
}
int Guess(int n){
for (register int i=1;i<=n;++i){
for (register int j=i+1;j<=n;++j)
if (fabs(g[i][i])<fabs(g[j][i])) swap(g[i],g[j]);
if (!g[i][i]) return -1;
for (register int j=1;j<=n;++j){
if (j==i) continue;
for (register int k=1;k<=n+1;++k)
if (k!=i) g[j][k]-=g[i][k]*g[j][i]/g[i][i];
g[j][i]=0;
}
}
for (register int i=1;i<=n;++i)
g[i][n+1]/=g[i][i];
return 1;
}