BZOJ3925: [Zjoi2015]地震后的幻想乡

138 篇文章 0 订阅
12 篇文章 0 订阅

这篇写得真的非常好

注意到题目这个提示:
对于n个[0,1]之间的随机变量x1,x2,…,xn,第k小的那个的期望值是k/(n+1)。

这说明我们要求修复时间的期望,只要求出用排名<=k的边恰好能使原图连通的概率就好了

然后推一下柿子
P(i)<=i使 P ( i ) 是 用 排 名 <= i 的 边 恰 好 能 使 原 图 连 通 的 概 率

Q(i)=mj=iP(j) Q ( i ) = ∑ j = i m P ( j )

L(i)<=i使 L ( i ) 是 用 <= i 的 边 不 能 使 原 图 连 通 的 概 率

i=1mP(i)im+1 ∑ i = 1 m P ( i ) ∗ i m + 1

mi=1Q(i)m+1 ∑ i = 1 m Q ( i ) m + 1

m1i=0L(i)m+1 ∑ i = 0 m − 1 L ( i ) m + 1

然后要求L(i),设 f[mask][i],g[mask][i] 表示用i条边使得点集mask 连通/不连通的方案数,做个 O(3nm2) O ( 3 n m 2 ) 的dp

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define lowbit(x) (x)&(-(x))
using namespace std;

const int maxn = 11;
const int maxm = 50;

int to[1<<maxn];
ll C[maxm][maxm];

int n,m,al;
int cnt[1<<maxn],v[maxn][maxn];
ll f[1<<maxn][maxm],g[1<<maxn][maxm];
// 不联通           联通

int main()
{
    for(int i=0;i<maxn;i++) to[1<<i]=i;
    C[0][0]=1;
    for(int i=1;i<maxm;i++)
    {
        C[i][0]=1;
        for(int j=1;j<=i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j];
    }

    scanf("%d%d",&n,&m); al=1<<n;
    for(int i=1;i<=m;i++)
    {
        int x,y; scanf("%d%d",&x,&y);
        v[x][y]=v[y][x]=1;
    }
    for(int i=1;i<al;i++)
    {
        int j=to[lowbit(i)]+1,ii=i^lowbit(i);
        cnt[i]=cnt[ii];
        for(int k=1;k<=n;k++) if(ii>>k-1&1)
            cnt[i]+=v[j][k];
    }

    g[0][0]=1;
    for(int i=1;i<al;i++)
    {
        int k=to[lowbit(i)]+1;
        for(int j=0;j<=cnt[i];j++)
        {
            for(int l=(i-1)&i;l;l=(l-1)&i) if(l>>k-1&1)
            {
                for(int z=0;z<=j&&z<=cnt[l];z++)
                    f[i][j]+=g[l][z]*C[cnt[i-l]][j-z];
            }
            g[i][j]=C[cnt[i]][j]-f[i][j];
        }
    }

    double re=0.0;
    for(int x=1;x<=m;x++) 
        re+=(double)f[al-1][x-1]/(double)C[cnt[al-1]][x-1];
    re/=m+1;
    printf("%.6lf\n",re);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值