版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/91457722
题目:BZOJ2337.
题目大意:给定一张
个点
条边的带边权无向连通图,求从点
到点
的异或和的期望.
,边权
.
看到位运算先想到拆位,显然每一位互不影响.
假设现在考虑某一位,我们设 表示这一位从点 出发到点 异或和为 的概率.
设
表示点
的度,容易列出方程:
然后我们根据这个方程高消一下即可得到最后的概率,也就可以求得期望了.
时间复杂度 .
注意自环不能加两次,只能当一条有向边算.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100,M=10000,C=30;
const double eps=1e-8;
int n,m;
struct side{
int y,next,v;
}e[M*2+9];
int lin[N+9],cs;
void Ins(int x,int y,int v){e[++cs].y=y;e[cs].v=v;e[cs].next=lin[x];lin[x]=cs;}
int deg[N+9];
double ans,mat[N+9][N+9];
void Gauss(){
int now=1;
for (int i=1;i<n;++i){
int r=now;
for (int j=now+1;j<n;++j)
if (abs(mat[j][i])>abs(mat[r][i])) r=j;
if (abs(mat[r][i])<eps) continue;
if (r^now) swap(mat[r],mat[now]);
double t=mat[now][i];
for (int j=1;j<=n;++j) mat[now][j]/=t;
for (int j=1;j<n;++j)
if (j^now){
t=mat[j][i];
for (int k=1;k<=n;++k) mat[j][k]-=t*mat[now][k];
}
++now;
}
for (int i=1;i<n;++i) mat[i][n]/=mat[i][i];
}
Abigail into(){
scanf("%d%d",&n,&m);
int x,y,v;
for (int i=1;i<=m;++i){
scanf("%d%d%d",&x,&y,&v);
Ins(x,y,v);++deg[x];
if (x^y) Ins(y,x,v),++deg[y];
}
}
Abigail work(){
for (int i=0;i<=C;++i){
for (int j=1;j<n;++j)
for (int k=1;k<=n;++k)
mat[j][k]=0;
for (int j=1;j<n;++j){
mat[j][j]-=1.0;
for (int k=lin[j];k;k=e[k].next)
if (e[k].y==n) mat[j][n]-=1.0*(e[k].v>>i&1)/deg[j];
else if (e[k].v>>i&1) mat[j][e[k].y]-=1.0/deg[j],mat[j][n]-=1.0/deg[j];
else mat[j][e[k].y]+=1.0/deg[j];
}
Gauss();
ans+=mat[1][n]*(1<<i);
}
}
Abigail outo(){
printf("%.3lf\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}