码迷,mamicode.com
首页 > 其他好文 > 详细

SDOJ 2605 闲荡

时间:2018-08-15 22:52:23      阅读:217      评论:0      收藏:0      [点我收藏+]

标签:输出   [1]   col   随机选择   width   play   cli   clu   位置   

描述

L 饭后无聊,便在 BugTown 里闲荡。

BugTown 共有 N 栋房屋和 M 条有向道路。每栋房屋都有一个非负整数 vi 作为标识。

BugTown 有一个特性十分神奇:从任意一个房屋离开后沿着路走再也不会回到原地。

L 想选一个房屋作为闲荡的起点,之后,他会随机选择一条当前位置能走的道路顺其 走过去,如此反复直到没有能走的道路。

由于极度无聊, L 发明了一个游戏以为消遣。他在闲荡的过程中记录已经过的房屋标 识的异或和(含起点)。闲荡完后,他会得到一个数。

L希望对每个房屋算出以它为起点能得到的数的期望值,但是他不知道怎么算,只好 求助于你。

输入

第一行两个正整数 N; M 分别为房屋数和道路数。

第二行 N 个数为 vi。

接下来 M 行每行两个整数 ai; bi 描述一条 ai 到 bi 的道路

输出

输出共 N 行。第 i 行一个实数表示以 i 号房屋为起点时最后得到的数的期望值。 实数四舍五入到小数点后三位

样例输入

3 2
1 2 3
1 2
2 3

样例输出

0.000
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 }
要看吗ovo

 

 

 

 
 

SDOJ 2605 闲荡

标签:输出   [1]   col   随机选择   width   play   cli   clu   位置   

原文地址:https://www.cnblogs.com/kylara/p/9484203.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!