【Luogu】P3211XOR和路径(高斯消元)

  题目链接

  唉我个ZZ……

  首先考虑到异或是可以每一位分开算的

  好的以后再碰见位运算题我一定先往按位开车上想

  然后设f[i]为从i点出发到终点是1的概率

  高斯消元解方程组即可。

  

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<bitset>
#define maxn 200
#define maxm 50020
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

inline int calc(int a,int b){    return (b>>a)&1;    }

struct Edge{
    int next,to,val,dis;
}edge[maxm*2];
int head[maxn],num;
inline void add(int from,int to,int val){
    edge[++num]=(Edge){head[from],to,val,0};
    head[from]=num;
}

double s[maxn][maxn];

double dl[maxn];
double ans[maxn];

void gauss(int n){
    for(int i=1;i<=n;++i){
        int now=i;
        for(int j=now;j<=n;++j)
            if(fabs(s[j][i])>fabs(s[now][i]))    now=j;
        if(now!=i)    swap(s[i],s[now]);
        double div=s[i][i];
        for(int j=i;j<=n+1;++j)    s[i][j]/=div;
        for(int j=i+1;j<=n;++j){
            double ret=s[j][i];
            for(int k=i;k<=n+1;++k){
                s[j][k]-=ret*s[i][k];
            }
        }
    }
    ans[n]=s[n][n+1];
    for(int i=n-1;i;--i){
        double now=0;
        for(int j=i+1;j<=n;++j)    now+=ans[j]*s[i][j];
        ans[i]=s[i][n+1]-now;
    }
}

int main(){
    int n=read(),m=read();
    for(int i=1;i<=m;++i){
        int from=read(),to=read(),val=read();
        dl[from]++;    add(from,to,val);
        if(from!=to){
            dl[to]++;
            add(to,from,val);
        }
    }
    double Ans=0;
    for(int i=0;i<32;++i){
        memset(s,0,sizeof(s));
        for(int j=1;j<=n;++j)    s[j][j]=1;
        for(int j=1;j<=num;++j)    edge[j].dis=calc(i,edge[j].val);
        for(int j=1;j<n;++j)
            for(int k=head[j];k;k=edge[k].next){
                int to=edge[k].to;
                if(edge[k].dis){
                    s[j][to]+=1.0/dl[j];    s[j][n+1]+=1.0/dl[j];
                }
                else s[j][to]-=1.0/dl[j];
            }
        //for(int j=1;j<=n;++j,printf("\n"))
        //    for(int k=1;k<=n+1;++k)    printf("%.3lf ",s[j][k]);
        gauss(n);
        //printf("\n");
        Ans+=ans[1]*(1<<i);
    }
    printf("%.3lf",Ans);
    return 0;
}

 

posted @ 2018-04-13 20:22  Konoset  阅读(196)  评论(0编辑  收藏  举报