• bzoj3925: [Zjoi2015]地震后的幻想乡


    仍然是自闭的%

    首先hint给了一个提示,对于n个[0,1]之间的随机变量x1,x2,...,xn,第k小的那个的期望值是k/(n+1)

    题目问的是最小生成树中最大边的e的期望,可以转化成最大边在所有边的期望排名*(m+1)

    设p(i)为刚好i条边就能够把所有点连起来的概率

    e(期望) = 1/m+1 * sigema(1~m) i*p(i)

         = 1/m+1 * sigema(1~m)i sigema(j>=i)p(j)

    sigema(j>=i)p(j)就是p的后缀和,等同于用i-1条边不能够把所有点连在一起的概率,令其为h(i-1)

    e(期望) = 1/m+1 * sigema(0~m-1) h(i)

    概率我们可以用i条边不能够把所有点连在一起的方案数f(i)除以用i条边随机出现的方案数计算

    e(期望) = 1/m+1 * sigema(0~m-1) f(i)/C(m,i)

    现在就要解决如何计算用i条边不能够把所有点连在一起的方案数

    设f[0][i][zt]表示用了i条边,不能够把为zt的点集都连在一起,1表示可以

    f[0][i][zt]= sigema(zt的子集tzt) sigema(j<i) f[1][j][tzt]*C[tot[zt^tzt]][i-j]

    意思是选择一个联通的子集用了j条边,剩下的边乱选(可以保证不会和tzt里面的点相连,也就是说tzt这个块是独立出来的)

    然后我们会发现一个问题,乱选的时候也有可能连出另一个联通块,这样会和枚举到这个子集的时候的计算重复 所以我们枚举子集的时候需要加一个条件,我们只用某一个点位于的联通块来更新答案

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    
    LL C[110][110];
    void initC(int m)
    {
        C[0][0]=1;
        for(int i=1;i<=m;i++)
        {
            C[i][0]=1;
            for(int j=1;j<=m;j++)
                C[i][j]=C[i-1][j-1]+C[i-1][j];
        }            
    }
    int tot[1100];
    struct edge{int x,y;}e[110];
    void inittot(int n,int m)
    {
        int li=(1<<n)-1;
        for(int zt=1;zt<=li;zt++)
        {
            tot[zt]=0;
            for(int i=1;i<=m;i++)
                if(((1<<e[i].x-1)&zt)&&((1<<e[i].y-1)&zt))
                    tot[zt]++;
        }
    }
    
    LL f[2][110][1100];//是否联通,用了的边数,点集 
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&e[i].x,&e[i].y);
        initC(m);inittot(n,m);
        
        int li=(1<<n)-1;
        for(int i=1;i<=n;i++)f[1][0][1<<i-1]=1;
        for(int zt=1;zt<=li;zt++)
        {
            int xt=(zt&-zt);
            for(int tzt=((zt-1)&zt);tzt;tzt=((tzt-1)&zt)) if(tzt&xt)
                for(int i=0;i<=tot[zt];i++)
                {
                    int tli=min(i,tot[tzt]);
                    for(int j=0;j<=tli;j++)
                        f[0][i][zt]+=f[1][j][tzt]*C[tot[zt^tzt]][i-j];
                    f[1][i][zt]=C[tot[zt]][i]-f[0][i][zt];
                }
        }
        double ans=0;
        for(int i=0;i<m;i++)ans+=double(f[0][i][li])/C[m][i];
        printf("%.6lf
    ",ans/(m+1));
        
        return 0;
    }
  • 相关阅读:
    Paypal开源nodejs框架研究(一)KrakenJs
    CoffeeScript 陷阱
    nodejs express route 的用法
    Moogoose实践之:Schema写全很重要,不然会把时间浪费在调错上!
    微软新一代输入法框架 TSF
    VC++在Win7和Win8系统下获得百度输入法的名字
    两款MongoDB的可视化管理工具
    网易开源游戏服务器框架-Pomelo实践(一)
    WinDbg之Page Heap实践
    MongoDB 备份与恢复的实践
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10188662.html
Copyright © 2020-2023  润新知