Luogu3211[HNOI2011]XOR和路径

Luogu3211[HNOI2011]XOR和路径

题面:洛谷

解析

这种位运算的题都是套路啊。很明显将边权拆位,列出转移方程高斯消元计算出每一位为1的期望,再累加贡献即可。

代码


// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<iostream>
#define N 105
#define M 10005
using namespace std;
int n,m; double ans=0.0;
inline int In(){
    char c=getchar(); int x=0,ft=1;
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1;
    for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
    return x*ft;
}
int h[N],deg[N],e_tot=0;
struct E{ int to,nex,d; }e[M<<1];
inline void add(int u,int v,int w){
    e[++e_tot]=(E){v,h[u],w}; h[u]=e_tot; ++deg[u];
}
double a[N][N],x[N];
int main(){
//  freopen("1.in","r",stdin);
//  freopen("test.out","w",stdout);
    n=In(); m=In();
    for(int i=1,u,v,w;i<=m;++i){
        u=In(); v=In(); w=In();
        if(u==v) add(u,v,w);
        else add(u,v,w),add(v,u,w);
    }
    for(int p=0;p<30;++p){
        memset(a,0,sizeof(a));
        for(int u=1;u<n;++u){
            a[u][u]=1.0; double w=1.0/deg[u];
            for(int i=h[u],v;i;i=e[i].nex){
                v=e[i].to; bool op=e[i].d&(1<<p);
                if(op) a[u][v]+=w,a[u][n+1]+=w;
                else a[u][v]-=w;
            }
        }
        a[n][n]=1.0;
        for(int i=1;i<=n;++i)
        for(int j=i+1;j<=n;++j)
        for(int k=n+1;k>=i;--k)
        a[j][k]-=a[i][k]*a[j][i]/a[i][i];
        for(int i=n;i;--i){
            x[i]=a[i][n+1];
            for(int j=n;j>i;--j) x[i]-=a[i][j]*x[j];
            x[i]/=a[i][i];
        }
        ans+=x[1]*(1<<p);
    }
    printf("%.3lf\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/pkh68/p/10526876.html
今日推荐