[HNOI2011]XOR和路径

[HNOI2011]XOR和路径

BZOJ
luogu
感觉跟[HNOI2013]游走差不多a...
然而就是这个异或要一位一位做
设f[k][u]表示u点到n的路径异或和二进制第k位为1的概率
考虑枚举u的出边,w(u,v)表示这条边第k位是0还是1

\[f[u]=\sum_{w(u,v)=0}\frac{f[v]}{d[u]}+\sum_{w(u,v)=1}\frac{1-f[v]}{d[u]} \]

处理好系数矩阵高斯消元
注意重自环只连单向边就行了
等等,还有f[n]=0

#include<bits/stdc++.h>
using namespace std;
const int _=105;
const double eps=1e-10;
int re(){
    int x=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}
int n,m,cnt;
int h[_],d[_];
double Ans;
double a[_][_],b[_],ans[_];
struct edge{int to,next,w;}e[20005];
void link(int u,int v,int w){
    e[++cnt]=(edge){v,h[u],w};
    h[u]=cnt;d[u]++;
}
void gauss(){
    for(int i=1;i<=n;i++){
        if(fabs(a[i][i])<eps)
            for(int j=i+1;j<=n;j++)
                if(fabs(a[j][i])>eps){
                    swap(a[i],a[j]);swap(b[i],b[j]);break;
                }
        if(fabs(a[i][i])<eps)continue;
        for(int j=i+1;j<=n;j++){
            if(fabs(a[j][i])<eps)continue;
            double s=a[j][i]/a[i][i];
            for(int k=i;k<=n;k++)a[i][k]*=s;b[i]*=s;
            for(int k=i;k<=n;k++)a[j][k]-=a[i][k];b[j]-=b[i];
        }
    }
    for(int i=n;i>=1;i--){
        ans[i]=b[i]/a[i][i];
        for(int j=1;j<i;j++)b[j]-=a[j][i]*ans[i];
    }
}
int main(){
    n=re(),m=re();
    for(int i=1,u,v,w;i<=m;i++){
        u=re(),v=re(),w=re();
        if(u^v)link(u,v,w),link(v,u,w);
        else link(u,v,w);
    }
    for(int k=0;k<=29;k++){
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<n;i++){
            a[i][i]=1;
            for(int j=h[i];j;j=e[j].next){
                int v=e[j].to;
                if(e[j].w>>k&1)a[i][v]+=1.0/d[i],b[i]+=1.0/d[i];
                else a[i][v]-=1.0/d[i];
            }
        }
        a[n][n]=1;gauss();Ans+=(1<<k)*ans[1];
    }
    printf("%.3f\n",Ans);return 0;
}
posted @ 2018-10-23 15:45  sdzwyq  阅读(121)  评论(0编辑  收藏  举报