zoukankan      html  css  js  c++  java
  • 【ZJOI2015】地震后的幻想乡

    题面

    https://www.luogu.org/problem/P3343

    题解

    一个几乎显然的暴力做法,枚举每一条边的大小关系,跑$Kruskal$,算出最长的边是第几小的,然后利用“对于$n$个$[0..1]$之间的随机变量$x_1,x_2,...,x_n$,第$k$小的那个的期望值是$frac{k}{n+1}$”的结论就可以知道这种情况下的时间期望是多少。(虽然这个方法也不是我自己想出来的),这个做法也照应了题面中“当然幽香会先使用一个更加神奇的大魔法来观察出每条边e_i的值,然后再选择完成时间最小的方案”这句话,即当知道$e_i$分布的情况后,就可以跑$Kruskal$算最小生成树。可以说这句话是对题解有暗示作用的。

    其实这道题很难,自己看了很多篇题解都没有看懂,最后看了https://blog.csdn.net/qq_41357771/article/details/88732154才搞懂,发现简洁的题解最适合我(我宁愿看简洁但是说不清楚的题解,也不愿看冗杂但讲的很清楚的题解)。想起去年在$qbxt$写过另外一道题,好像叫苹果树,是$P$大的李昊出的($orz lhz$),和这道题思路类似。记得当时就没有弄懂。

    总结一下这几天刚概率期望的经验,总是把概率期望当成计数问题做,用合法方案除以总方案数,这样思考的方程也更严谨一些,因为如果一步就直接写关于概率/期望的方程就全凭感觉了。(尤其是总方案数显然的题,比如随机数生成器)

    对于要取膜的题而言,可以把方案无损转化成概率期望。对于这样只要求一个笼统的数字的题,当数据范围很大时,精度是不够的,要求直接写出概率/期望的式子,还有一种可能是高斯消元和矩阵快速幂(概率即期望),尤其是在$n le 500$时。

    另一个很好的思路是期望转概率,这个思路最初是$aysn$告诉我的,最后把期望化成几个概率的合式,这几道题应该都是这样。

    如果只从期望的角度考虑的话,可能利用到期望的线性性,然后考虑贡献(某$CF$题)。

    回到这道题。

    这个方法自然是对暴力的优化。

    令$f[i][s]$为考虑了前$i$条边,$s$集合里面的元素联通的方案数。

    令$g[i][s]$为考虑了前$i$条边,$s$集合里面的元素不联通的方案数。

    显然,有$$f[i][s]+g[i][s]=C_{cnt[s]}^{i}$$

    你可能会问,前$i$条是哪$i$条,事实上,既然是对暴力算法的优化,前$i$条就是权值最小的$i$条边,我们并不知道是哪$i$条,并且我们也不需要知道,因为已经知道了这个联通块的状态,答案只取决于最后加进去的一条边,冗余的边显然是没有贡献的,所以我们不需要知道。我们可以把它理解成任意$i$条边,进一步,更神奇的,转移的时候,我们也不需要枚举当前的边是哪一条,但是它一定是$s$集合中元素与元素间的。

    对于转移的情况,有

    $$g[i][s]=sum_{s0 subset s,0le k<i}{f[k][s0]cdot C_{cnt[soplus s0]}^{i-k}}$$

    我们可以这么理解,就是我们让一个子集一定联通,然后另一部分只能互相联通,即两部分之间一定不连通。

    但是这样写很$fake$,因为会多情况,所以我们强制选一个点$x$(随机的,当年,李昊老师说直接选$1$号点),让$x in s0$恒成立,就可以做到不重不漏了。

    其实这一步我也不知道是为什么,但已经不是第一次见了,所以就当做一个定理吧。

    算答案已经是老生常谈了,但是这个和其他的题不一样,直接用$g[i][U]$算,即答案$>i$的所有方案数之和,这样的话,我们连乘$i$都不需要了,直接把他们都加起来就好了。

    说实话,这道题联通子图的边数竟然是有意义的,这还是我第一次见到。

    记一下两个细节吧,因为取的是大于号,所以$g[i][U]$要从$0$开始加,第二是$g[0][i]=1(i.countge 2)$

    $mbox{update 2019.10.31 zrt}$说是联通图计数,对于边集给定的情况枚举自己,如果边集是全集,就可以直接乘组合数。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<vector>
    #define ri register int
    #define N 12
    #define M 46
    #define mod 666623333
    #define LL long long
    
    using namespace std;
    
    inline int read() {
        int ret=0,f=0; char ch=getchar();
        while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
        while (ch>='0' && ch<='9') ret*=10,ret+=ch-'0',ch=getchar();
        return f?-ret:ret;
    }
    
    LL c[100][100];
    int cnt[1<<N];
    LL f[M][1<<N],g[M][1<<N];
    int has[N][N];
    int n,m;
    int u[M],v[M];
    
    int lowbit(int x) {
      return x&(-x);
    }
    int bit(int x) {
      for (ri i=0;i<n;i++) if (x&(1<<i)) return i;
      return -1;
    }
    
    int main() {
        n=read(); m=read();
      for (ri i=1;i<=m;i++) {
        u[i]=read()-1; 
        v[i]=read()-1;
        has[u[i]][v[i]]=has[v[i]][u[i]]=1;
      }
      cnt[0]=0;
      for (ri s=1;s<(1<<n);s++) {
        int t=lowbit(s),t0=bit(t);
        cnt[s]=cnt[s-t];
        for (ri j=0;j<n;j++) if ( ((s-t)&(1<<j)) && has[t0][j]) cnt[s]++;
      }
      c[0][0]=1; c[1][0]=1; c[1][1]=1;
      for (ri i=2;i<=m;i++) {
        c[i][0]=1;
        for (ri j=1;j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
      }
      for (ri i=0;i<(1<<n);i++) g[0][i]=1;
      for (ri i=0;i<n;i++) f[0][1<<i]=1,g[0][1<<i]=0;
    
      for (ri i=1;i<=m;i++)
        for (ri s=1;s<(1<<n);s++) {
          int t=lowbit(s);
          for (ri s0=(s-1)&s;s0;s0=(s0-1)&s) if (s0&t)
            for (ri k=0;k<=i;k++) g[i][s]+=f[k][s0|t]*c[cnt[s^s0]][i-k];
          f[i][s]=c[cnt[s]][i]-g[i][s];
        }
      double ans=0;
      int U=(1<<n)-1;
      for (ri i=0;i<=m;i++) ans+=g[i][U]*1.0/c[cnt[U]][i];
      printf("%.6lf
    ",ans/(m+1));
      return 0;
    }
  • 相关阅读:
    sourceTree免密码校验
    elasticsearch 服务安全配置
    qconf 介绍
    解决mysql不能远程登录的问题
    从git上下载代码并导入eclipse
    MAVEN 工程打包resources目录外的更多资源文件
    也谈BIO | NIO | AIO (Java版--转)
    web.xml 配置中classpath: 与classpath*:的区别
    Java @override报错的解决方法
    maven上传自定义jar到本地仓库
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11707631.html
Copyright © 2011-2022 走看看