1. 程式人生 > >[HNOI2011]XOR和路徑

[HNOI2011]XOR和路徑

正常 直接 概率 sta gist val 轉移 要求 string

題面
一道期望大火題(表示看了zsy大佬和ycb大佬的題解才過去的orz)

遞推期望,因為是異或和,按照正常方法會很難,於是考慮按位DP(套路吧)
設狀態的時候需要註意
如果設f[x]表示從1號節點到達x號節點且異或和為1的概率
那麽在轉移的時候,因為到達n號節點的時候就已經停止,所以f[n]不能轉移;而我們又必須求出f[n],因此必須先對除n以外的所有點進行計算,再推到n,這樣會很麻煩
於是想到倒著推,設f[x]表示從x號節點到達n號節點且異或和為1的概率,答案為f1,雖然說也不能從f[n]轉移,但因為要求解的不是f[n]所以讓就變得可行了

通過邊進行轉移:
\[f[u]=\sum_{v}\frac{f[v]}{d[u]}*[(u,v)==0]+\sum_{v}\frac{1-f[v]}{d[u]}*[(u,v)==1]\]


意即該位權值為1的點通過0邊和該位權值為0的點通過1邊到達點u所得的該位權值都是1

由於每個f[u]都和另外的f[v]產生依賴關系,故無法直接遞推求解
高斯消元大顯身手啦!!!!!!

接下來奉上本蒟蒻醜陋的代碼


#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<vector>
#include<cstdio>
#include<string> #include<bitset> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #define mp make_pair #define pb push_back #define RG register #define il inline using namespace std; const int mod=1e9+7; const int N=110; const double
eps=1e-10; typedef unsigned long long ull; typedef vector<int>VI; typedef long long ll; typedef double dd; il ll read(){ RG ll data=0,w=1;RG char ch=getchar(); while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘))ch=getchar(); if(ch==‘-‘)w=-1,ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘)data=data*10+ch-48,ch=getchar(); return data*w; } int n,m,head[N],nxt[N*N*2],to[N*N*2],val[N*N*2],d[N],cnt; il void add(int u,int v,int w){ to[++cnt]=v;d[v]++; val[cnt]=w; nxt[cnt]=head[u]; head[u]=cnt; } dd S[35][N][N],ans[35][N],sum; il bool gauss(int a){ //高斯消元部分 for(RG int i=1;i<=n;i++){ for(RG int j=i;j<=n;j++) if(abs(S[a][j][i])>eps){ swap(S[a][j],S[a][i]);break; } if(abs(S[a][i][i])<=eps)return 0; for(RG int j=i+1;j<=n;j++){ ans[a][j]-=ans[a][i]*S[a][j][i]/S[a][i][i]; for(RG int k=n;k>=i;k--) S[a][j][k]-=S[a][i][k]*S[a][j][i]/S[a][i][i]; } } for(RG int i=n;i;i--){ for(RG int j=i+1;j<=n;j++) ans[a][i]-=S[a][i][j]*ans[a][j]; ans[a][i]/=S[a][i][i]; } return 1; } int main() { n=read();m=read(); for(RG int i=1,u,v,w,t;i<=m;i++){ u=read();v=read();w=read();t=0; add(u,v,w);if(u!=v)add(v,u,w); } //這裏是統計系數 for(RG int u=1;u<n;u++){ for(RG int i=0;i<=32;i++)S[i][u][u]+=1.0; for(RG int i=head[u];i;i=nxt[i]){ RG int v=to[i],t=0; while(t<=32){ S[t][u][v]+=((val[i]&1)?1:(-1))*1.0/(d[u]*1.0); ans[t][u]+=((val[i]&1)?1:0)*1.0/(d[u]*1.0); val[i]>>=1;t++; } } }for(RG int i=0;i<=32;i++)S[i][n][n]+=1.0; //這樣可以保證最後f[n]==0消除f[n]的影響 for(RG int i=0;i<=32;i++)gauss(i); for(RG ll i=0,x=1;i<=32;i++){sum+=ans[i][1]*x;x<<=1;} //按位統計答案 printf("%.3lf\n",sum); return 0; }

註:還有一道[HNOI2013]遊走和此題思想類似,仍未解決。明天再戰!!!

[HNOI2011]XOR和路徑