pre.cjk { font-family: "Droid Sans Fallback", monospace }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }
和期望有关的题一脸懵逼QAQ
题目要求的是异或和的期望,所以就把二进制的每一位都搞一遍,最后答案就是每一位的期望和。
然后对于每一位,推出一个很鬼畜的DP方程:f[i]表示i这个点到n的概率。 f[n][n]=1;然后枚举i,枚举i连的每个点,如果这条路的边权为1(这里指的是二进制)f[i]+=(1-f[j])/in[i]。否则f[i]+=f[j]/in[i],in[i]表示的是每个点连接的边的数量。
这里需要注意,自环的边只能加一条,in也只能+1。
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<ctime> 6 #include<cmath> 7 #include<string> 8 #include<vector> 9 #include<cstdio> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 using namespace std; 15 struct data{ 16 int nex,to,w; 17 }e[20010]; 18 int n,head[110],edge=0; 19 double a[110][110],in[110]; 20 void add(int from,int to,int w){ 21 e[++edge].nex=head[from]; 22 e[edge].to=to; 23 e[edge].w=w; 24 head[from]=edge; 25 } 26 void gauss(){ 27 for(int i=1;i<=n;i++){ 28 int t=i; 29 while(!a[t][i] && t<=n) t++; 30 if(t>n) continue; 31 for(int j=1;j<=n+1;j++) swap(a[t][j],a[i][j]); 32 double k=a[i][i]; 33 for(int j=i;j<=n+1;j++) a[i][j]/=k; 34 for(int j=1;j<=n;j++) 35 if(j!=i && a[j][i]){ 36 k=a[j][i]; 37 for(int p=i;p<=n+1;p++) 38 a[j][p]-=k*a[i][p]; 39 } 40 } 41 } 42 int main() 43 { 44 freopen("!.in","r",stdin); 45 freopen("!.out","w",stdout); 46 int m,x,y,z; 47 double ans=0.0; 48 scanf("%d%d",&n,&m); 49 for(int i=1;i<=m;i++){ 50 scanf("%d%d%d",&x,&y,&z); 51 if(x!=y) add(x,y,z),add(y,x,z),in[x]++,in[y]++; 52 else add(x,y,z),in[x]++; 53 } 54 for(int p=0;p<=30;p++){ 55 memset(a,0,sizeof(a)); 56 for(int i=1;i<n;i++){ 57 a[i][i]=1.0; 58 for(int j=head[i];j;j=e[j].nex) 59 if(e[j].w&(1<<p)) a[i][e[j].to]+=1.0/in[i],a[i][n+1]+=1.0/in[i]; 60 else a[i][e[j].to]-=1.0/in[i]; 61 } 62 a[n][n]=1.0; 63 gauss(); 64 ans+=a[1][n+1]*1.0*(1<<p); 65 } 66 printf("%.3lf",ans); 67 return 0; 68 }
这看起来像一个动态规划,但是这是一个无向图,DP好像跑不了,那怎么办?
对于每一个i,都会有一个线性方程:
f[i]=f[j1]/in[i]+(1-f[j2])/in[i]+......
然后就会发现有n个方程,然后就可以用高斯消元了......简直妙不可言。
时间: 2024-10-16 04:53:15