zoukankan      html  css  js  c++  java
  • 【NOIP模拟】闲荡

    题面

    L 饭后无聊,便在 BugTown 里闲荡。  BugTown 共有 N 栋房屋和 M 条有向道路。每栋房屋都有一个非负整数 vi 作为标识。  BugTown 有一个特性十分神奇:从任意一个房屋离开后沿着路走再也不会回到原地。  L 想选一个房屋作为闲荡的起点,之后,他会随机选择一条当前位置能走的道路顺其 走过去,如此反复直到没有能走的道路。  由于极度无聊, L 发明了一个游戏以为消遣。他在闲荡的过程中记录已经过的房屋标 识的异或和(含起点)。闲荡完后,他会得到一个数。  L希望对每个房屋算出以它为起点能得到的数的期望值,但是他不知道怎么算,只好 求助于你。

    对于 10% 的数据, N <= 5; M <= 10。  对于 30% 的数据, N, M<= 50。  对于 70% 的数据, N, M <=1000。  对于 100% 的数据, 1 <= N,M <= 1e5; 0 <= vi <= 1e9。

    分析

    期望dp.

    很久没碰了,今天算是彻头彻尾好好复习了一下

    通俗地讲,我们定义一个随机变量,数学期望是随机变量取值与概率的乘积之和。

    而此题的随机变量取值就是异或和,概率就是u的出度分之一。

    此题70%数据才1000,可以过n,而我一个julao同学跑到了90分的暴力(直接枚举每个点,直到dfs到叶子结点)

    要考虑如何递推,首先要知道关于期望的两个结论:

    1.E(A+B)=E(A)+E(B),这意味着我们可以把要求的期望拆分成和的形式

    2.E(K*A)=K*E(A),其中K为常数。这意味着我们一定条件下能简化求期望值的复杂度。

    因为异或是在二进制位上进行的操作,我们可以把要求的期望值写成 X=∑ai  *  2i

    E(X)=∑E(ai  *  2i)=∑E(a)*  2i

    所以我们只需要求E(a)即可

    设P为概率,v为当前点的标识值,此时标识值为10进制处理,它是随机变量

    但当依次对每个二进制位操作时,二进制的0和1就成为了新的随机变量,根据两条性质,它们最后通过乘2的次方可以被还原回去

    则有 E(a)=∑v *P(ai=v) = 0* P(ai=0) + 1*P(ai=1)   = P(ai=1)

    所以求的期望值实际上是每个二进制位为1的概率

    用f[c][d]表示从点c出发计算的值的二进制当前位为d(d=0或1)的概率。

    对于没有出边的点,我们可以直接得出值(如果这个点的这一位为g,那么f[c][g] = 1f[c][g ^ 1] = 0)。

    对于其他的f,我们可以递推得到。具体实现可以用记忆化搜索或先求拓扑序再dp

    #include<bits/stdc++.h>
    using namespace std;
    #define N 100010
    int n,m,tot,cnt;
    double ans[N];
    int val[N],first[N],in[N],s[N];
    double f[N][2];
    queue<int>q;
    struct email
    {
        int u,v;
        int nxt;
    }e[N*4];
    inline void add(int u,int v)
    {
        e[++cnt].nxt=first[u];first[u]=cnt;
        e[cnt].u=u;e[cnt].v=v;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&val[i]);
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);in[v]++;
        }
        for(int i=1;i<=n;i++)
            if(!in[i])
                q.push(i);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            s[++tot]=u;
            for(int i=first[u];i;i=e[i].nxt)
            {
                int v=e[i].v;
                in[v]--;
                if(!in[v])
                    q.push(v);
            }        
        }
        for(int i=0;i<30;i++)
            for(int j=n;j>=1;j--)
            {
                int u=s[j],siz=0;
                int g=((val[u]>>i)&1);
                for(int k=first[u];k;k=e[k].nxt)
                    siz++;
                if(!siz)
                {
                    f[u][g]=1.0;
                    f[u][g^1]=0.0;
                }
                else
                {
                    double p=1.0/siz;
                    f[u][1]=0.0;f[u][0]=0.0;
                    for(int k=first[u];k;k=e[k].nxt)
                    {
                        int v=e[k].v;
                        f[u][0]+=f[v][g]*p;//相同为0,不同为1 
                        f[u][1]+=f[v][g^1]*p;
                    }
                }
                ans[u]+=(1<<i)*f[u][1];
            }
        
        for(int i=1;i<=n;i++)
            printf("%.3lf
    ",ans[i]);
        return 0;
    }
    “Make my parents proud,and impress the girl I like.”
  • 相关阅读:
    变量提升
    前端UI框架和JS类库
    ES6---Map数据结构
    ES6---Set数据结构
    Array.from//Array.of的用法
    闭包的理解和应用场景
    vue-router 的用法
    原型链和作用域链的理解
    WordPress更换了域名 主页、文章、图片路径错误 解决办法
    wordpress 安装新的主题后启动后报错
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9483825.html
Copyright © 2011-2022 走看看