zoukankan      html  css  js  c++  java
  • P3343 [ZJOI2015]地震后的幻想乡

    传送门

    由提示可以知道,如果把图中的边从小到大依次加入,在加入第 $k$ 条边时图恰好联通,那么期望花费为 $frac{k}{m+1}$

    注意到期望花费和加入边数成正比,发现可以看成每一条加入后不使图联通的边的贡献之和,每条不使图联通的边的贡献即为 $frac{1}{m+1}$

    那么如果能算出 $f[i]$ 表示加入第 $i$ 条边时图仍然不连通的概率,那么它对答案的贡献就是 $frac {1}{m+1}$,期望贡献即为 $frac{f[i]}{m+1}$

    那么枚举每一条不使图联通的边,可以得到 $ans=frac{1}{m+1}sum_{k=0}^{m}f[k]$(注意这里有算到第 $0$ 条边的贡献)

    然后现在的问题就是求这个东西的概率,考虑求出合法方案数,然后除以总方案数即可得到概率

    设 $f[S][i]$ 表示当前点集为 $S$ ,加入了 $i$ 条边仍然不联通的方案数,同理设 $g[S][i]$ 表示联通的方案数

    那么显然有 $f[S][i]+g[S][i]=inom{D_S}{i}$ ,其中 $D_S$ 表示点集 $S$ 的总边数

    现在考虑 $f$ 的转移,显然考虑枚举这个不连通块中的某个联通块子集,那么容易想到转移 $f[S][i]=sum_{T in S}sum_{j=0}^{min(i,D_T)} g[T][j]inom{D_{S-T}}{i-j}$

    但是发现这样对于 $f[S][i]$ 的每个方案都多算了那个方案中联通块个数次

    然后这里就有一个神仙操作,钦定某个点一定在 $T$ 中,那么这样就不会重复算到一种方案了(因为这个方案的其他联通块都不会枚举到了)

    然后算完 $f[S][i]$ 那么 $g[S][i]=inom{D_S}{i}-f[S][i]$

    最后 $ans=frac{1}{m+1}sum_{k=0}^{m}frac{f[U][k]}{inom{m}{k}}$,显然 $U$ 表示全集,$inom{m}{k}$ 就是总方案

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    typedef double db;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=11,M=107;
    int n,m,cnt[(1<<N)+7],a[M],b[M];
    ll C[M][M],f[(1<<N)+7][M],g[(1<<N)+7][M];
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=m;i++)
            a[i]=read()-1,b[i]=read()-1;
        int mx=(1<<n)-1;
        for(int i=1;i<=mx;i++)
            for(int j=1;j<=m;j++)
                if((i>>a[j])&1 && (i>>b[j])&1) cnt[i]++;
        for(int i=0;i<=m;i++)
        {
            C[i][0]=1;
            for(int j=1;j<=i;j++)
                C[i][j]=C[i-1][j]+C[i-1][j-1];
        }
        for(int o=1;o<=mx;o++)
            for(int j=0;j<=cnt[o];j++)
            {
                for(int op=(o-1)&o;op;op=(op-1)&o)
                    if(op&(o&-o))
                        for(int k=0;k<=min(j,cnt[op]);k++)
                            f[o][j]+=g[op][k]*C[cnt[o^op]][j-k];
                g[o][j]=C[cnt[o]][j]-f[o][j];
            }
        db ans;
        for(int i=0;i<=m;i++) ans+=1.0*f[mx][i]/C[m][i];
        ans/=m+1; printf("%.6lf
    ",ans);
        return 0;
    }
  • 相关阅读:
    恢复IE下载对话框[转]
    意外删除Oracle数据文件(dbf),恢复oralce库的解决办法Oracle错误代码:ORA01033
    [转].net的一些问题
    解决了一个ASP.NET无法接受中文参数值的情况
    修改IIS6的默认设置,扩充上传文件的大小
    在ASP.NET中Request取不到正确的中文参数问题解决办法[base64编码/解码]
    使用微软的TreeView控件有的客户端有脚本错误的问题
    [转]几种调用WebService的方法
    电脑操作精典密芨60式 【转】
    初始化时间下列框的脚本
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11707488.html
Copyright © 2011-2022 走看看