2337: [HNOI2011]XOR和路径 高斯消元解期望方程 概率与期望DP

居然没被卡精度,高斯消元居然一边写对了,sb错误居然没犯。。
如此傻逼的我也能1A真是感动。

因为要求的是 xor 的期望,我们可以按位计算每位的期望再相加。
考虑每一位,我们令 d[i] 表示点 i 的出度,我们令 f[i] 表示从 i 走到 n 这一位的 xor 和为 1 的概率,那么有

f[i]=j=1d[i]f[j]d[i](edge(i,j)=0),1f[j]d[i](edge(i,j)=1)

玛雅我写的式子好傻逼意会一下就好了
然后我们可以高斯消元来解这个方程。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 105
#define M 10005
#define eps 1e-8
using namespace std;
int n,m,cnt;
double ans,a[N][N];
int head[N],d[N];
int next[M<<1],list[M<<1],key[M<<1];
inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}
inline void insert(int x,int y,int z)
{
    d[x]++;
    next[++cnt]=head[x];
    head[x]=cnt;
    list[cnt]=y;
    key[cnt]=z;
}
inline void Gauss()
{
    int y;
    for (int i=1;i<n;i++)
    {
        for (y=i;y<n;y++)
            if (fabs(a[y][i])>eps) break;
        if (y>=n) continue;
        if (y!=i)
            for (int j=1;j<=n+1;j++) swap(a[i][j],a[y][j]);
        double t=a[i][i];
        for (int j=1;j<=n+1;j++) a[i][j]/=t;
        for (int j=1;j<n;j++)
            if (j!=i)
            {
                double t=a[j][i];
                for (int k=1;k<=n+1;k++)
                    a[j][k]-=a[i][k]*t;
            }
    }
}
int main()
{
    n=read(); m=read();
    for (int i=1;i<=m;i++)
    {
        int u=read(),v=read(),w=read();
        insert(u,v,w); 
        if (u!=v) insert(v,u,w);
    }
    for (int k=0;k<=30;k++)
    {
        memset(a,0,sizeof(a));
        for (int i=1;i<=n;i++) a[i][i]+=(double)d[i];
        for (int x=1;x<n;x++)
            for (int i=head[x];i;i=next[i])
                if (key[i]&(1<<k)) a[x][list[i]]+=1.0,a[x][n+1]+=1.0;
                else a[x][list[i]]-=1.0;
        Gauss();
        ans+=a[1][n+1]*(1<<k);
    }
    printf("%.3lf\n",ans);
    return 0;
}

你可能感兴趣的:(2337: [HNOI2011]XOR和路径 高斯消元解期望方程 概率与期望DP)