[BZOJ]2337: [HNOI2011]XOR和路径 期望+高斯消元

来源:互联网 发布:linux登陆ftp服务器 编辑:程序博客网 时间:2024/05/29 16:52

Description
这里写图片描述

题解:

好题啊!以前都不知道高斯消元还能这样用!看到xor,我们可以想到拆位,这样算出每位为1的期望然后乘上一个权值就是答案了。假设我们现在处理到第j位,为了方便,我们把每条边的权值看做它的第j位,令f[i]表示i到n这一位为1的期望,我们可以分这条边的权值为0或1的情况讨论,很容易推出式子,我就懒得写了,然后显然f[n]=0(因为走到n就停下)。为什么这里不定义状态为从1走到i的期望呢?因为不好推,没有一个确定的f。又因为这个图不是DAG,所以f不能直接推出来,而且f之间会互相影响,所以选择用高斯消元解方程求出f

代码:

#include<bits/stdc++.h>using namespace std;#define LL long longconst long double eps=1e-8;const int Maxn=110;int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}    return x*f;}int n,m,degree[Maxn];struct Edge{int y,next,d;}e[20010];int last[Maxn],len=0;void ins(int x,int y,int d){    int t=++len;    e[t].y=y;e[t].d=d;e[t].next=last[x];last[x]=t;}long double a[Maxn][Maxn];void gauss(){    for(int i=1;i<n;i++)    {        if(abs(a[i][i])<=eps)        {            for(int j=i+1;j<n;j++)            if(abs(a[j][i])>eps)            {                for(int k=i;k<=n+1;k++)swap(a[j][k],a[i][k]);                break;            }        }        for(int j=i+1;j<n;j++)        if(abs(a[j][i])>eps)        {            long double t=a[j][i]/a[i][i];            for(int k=i;k<=n+1;k++)a[j][k]-=t*a[i][k];        }    }    for(int i=n-1;i;i--)    {        for(int j=i+1;j<=n;j++)        a[i][n+1]-=a[i][j]*a[j][n+1];        a[i][n+1]/=a[i][i];    }}int main(){    n=read();m=read();    for(int i=1;i<=m;i++)    {        int x=read(),y=read(),d=read();        degree[y]++,ins(x,y,d);        if(x!=y)degree[x]++,ins(y,x,d);    }    long double ans=0.0;    for(int j=0;j<31;j++)    {        for(int p=1;p<=100;p++)        for(int q=1;q<=101;q++)        a[p][q]=0.0;        for(int x=1;x<n;x++)        {            a[x][x]=(long double)(degree[x]);            for(int i=last[x];i;i=e[i].next)            {                int y=e[i].y,d=((e[i].d>>j)&1);                if(d)a[x][y]+=1.0,a[x][n+1]+=1.0;                else a[x][y]-=1.0;            }        }        gauss();ans+=a[1][n+1]*(long double)(1<<j);    }    printf("%.3Lf",ans);}
阅读全文
1 0