【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; }