SDOJ 2605 闲荡
描述
L 饭后无聊,便在 BugTown 里闲荡。
BugTown 共有 N 栋房屋和 M 条有向道路。每栋房屋都有一个非负整数 vi 作为标识。
BugTown 有一个特性十分神奇:从任意一个房屋离开后沿着路走再也不会回到原地。
L 想选一个房屋作为闲荡的起点,之后,他会随机选择一条当前位置能走的道路顺其 走过去,如此反复直到没有能走的道路。
由于极度无聊, L 发明了一个游戏以为消遣。他在闲荡的过程中记录已经过的房屋标 识的异或和(含起点)。闲荡完后,他会得到一个数。
L希望对每个房屋算出以它为起点能得到的数的期望值,但是他不知道怎么算,只好 求助于你。
输入
第一行两个正整数 N; M 分别为房屋数和道路数。
第二行 N 个数为 vi。
接下来 M 行每行两个整数 ai; bi 描述一条 ai 到 bi 的道路
输出
输出共 N 行。第 i 行一个实数表示以 i 号房屋为起点时最后得到的数的期望值。 实数四舍五入到小数点后三位
样例输入
1 2 3
1 2
2 3
样例输出
1.000
3.000
对于 10% 的数据, N <= 5; M <= 10。
对于 30% 的数据, N, M<= 50。
对于 70% 的数据, N, M <=1000。
对于 100% 的数据, 1 <= N,M <= 1e5; 0 <= vi <= 1e9。
----------------------------------------------------------------------------------------------
数学期望真是一个大坑!异或的相关计算也是!趁这道题复习了一下这两点。
数学期望:是试验中每次可能结果的概率乘以其结果的总和
·这是公式:
·它有两个结论:
1.E(A + B) = E(A) + E(B)
2.E(k*A) = k*E(A)
看起来没什么用,但实际上太了不起啦(23333
好的然后我们来看这道题。
先从期望入手:
设某个点的标识为k,因为题目涉及到异或,所以有
k的二进制表示:
则:
于是就转化为求E(ai)
而这时候,玄(投机)学(取巧)操作就出现了:因为ai只能为0或1,所以我们可以通过等式拆开化简来消去系数为0的项:
从此,我们将求E(ai)转化为直接求ai=1的概率,即只需要处理每个点出发得到的第i位为1的概率。
接下来我们要构造的是dp转移方程:
用f[c][d]表示从c点出发,此数位为d的概率。
枚举当前到的点u,此时数位为g,v为u的某出边,double p=1.0/出边数,以下分为两种情况:
1. u 没有出边,则有:f[u][g]=1; f[u][g^1]=0;//为g(0,1)的概率为1,为g相反的数(1,0)的概率为0
2. u有出边,则有递推式: f[u][0]+=f[v][g]*p; f[u][1]+=f[v][g^1]*p; //儿子当位为g,异或后为0,反之亦然
最后看回大局,最初应该先做一次拓扑排序,因为我们是以图的一层一层向下转移的。
就酱~
1 #include<bits/stdc++.h> 2 #define N 100010 3 using namespace std; 4 int val[N],n,m; 5 struct rockdu 6 { 7 int u,v,nxt; 8 }e[N*2]; 9 int first[N],cnt; 10 int tot; 11 void ade(int u,int v) 12 { 13 e[++cnt].nxt=first[u];first[u]=cnt; 14 e[cnt].v=v;e[cnt].u=u; 15 } 16 int deg[N],seq[N],sn; 17 double f[N][2]; 18 double ans[N]; 19 queue<int> q; 20 int main() 21 { 22 scanf("%d%d",&n,&m); 23 for(int i=1;i<=n;i++) 24 scanf("%d",&val[i]); 25 for(int i=1;i<=m;i++) 26 { 27 int a,b; 28 scanf("%d%d",&a,&b); 29 ade(a,b); 30 ++deg[b]; 31 } 32 for(int i=1;i<=n;i++) 33 if(deg[i]==0) q.push(i); 34 while(!q.empty()) 35 { 36 int u=q.front(); q.pop(); 37 seq[++sn]=u; 38 for(int i=first[u];i;i=e[i].nxt) 39 { 40 int v=e[i].v; 41 deg[v]--; 42 if(deg[v]==0) q.push(v); 43 } 44 } 45 for(int i=0;i<30;i++) 46 for(int j=n;j>=1;j--) 47 { 48 int u=seq[j],son=0; 49 int g=( (val[u]>>i)&1 ); 50 for(int x=first[u];x;x=e[x].nxt) 51 ++son;//记录儿子个数 52 if(son==0) 53 { 54 f[u][g]=1.0; 55 f[u][g^1]=0.0; 56 } 57 else 58 { 59 double p=1.0/son; 60 f[u][0]=f[u][1]=0.0;//初始化 61 for(int x=first[u];x;x=e[x].nxt) 62 { 63 int v=e[x].v; 64 f[u][0]+=f[v][g]*p; 65 f[u][1]+=f[v][g^1]*p; 66 } 67 } 68 ans[u]+=f[u][1]*(1<<i); 69 } 70 for(int i=1;i<=n;i++) 71 printf("%.3lf\n",ans[i]); 72 return 0; 73 }