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

    ZJOI2015 地震后的幻想乡

    我们其实只需要边的相对的发小关系,我们只要知道这个边是第几就可以了,因为如果知道它是第几就知道权值期望是 $ frac i {m+1} $

    所以我们考虑这样一个dp, $ dp[S][i] $ 表示加入第 $ i $ 小的边权时 $ S $ 是联通的方案数。

    由于一个显然的前缀和,我们知道答案其实就是

    [sum_i frac i {m+1} imes ( frac {dp[S][i]}{inom i m} - frac{dp[S][i-1]}{inom {i - 1} m} ) ]

    但是这个 $ dp $ 咋推呢?我们可以类似 HDU5552 的做法来推,一样是算联通图的数量,所以可以一样算不联通图的数量,考虑 $ f[S][i] $ 表示 $ S $ 加入 $ i $ 边后不联通图的方案数量。

    不联通图的方案可以一样套用那个题的做法,考虑固定一个点,并且由这个点连出一个联通图,并且剩下的点自己连,和这个点的联通图没得关系。

    由于最后连成的图肯定是包含这个点的,所以可以不重不漏统计所有方案。于是我们可以写出方程:

    [f[S][i] = dp[T][j] + inom {d[S ackslash T]} {i-j} ]

    其中 $ T $ 是 $ S $ 的一个子集,并且固定的这个点在 $ T $ 里面, $ d[S] $ 表示 $ S $ 点集在图里的边的数量。

    而且 $ f $ 和 $ dp $ 明显是互补的,所以和为 $ inom {d[S]} {i} $。

    这题就做完啦。

    但是想想组合数可不可能太大导致爆炸了呢?发现这题组合数最大也就 $ C_{50}^{10} $ 这个级别(其实更小),才 $ 10^{11} $ 左右,很稳。

    #include "iostream"
    #include "algorithm"
    #include "cstring"
    #include "cstdio"
    #include "vector"
    using namespace std;
    #define int long long
    #define MAXN 12
    #define chkmn( a , b ) ( (a) > (b) ? (a) = (b) , 1 : 0 )
    #define chkmx( a , b ) ( (a) < (b) ? (a) = (b) , 1 : 0 )
    int n , m;
    long long dp[MAXN * MAXN][1 << MAXN] , f[MAXN * MAXN][1 << MAXN] , d[1 << MAXN];
    vector<int> G[MAXN];
    long long C[51][51];
    signed main() {
        cin >> n >> m;
        C[0][0] = 1;
        for( int i = 1 ; i <= m ; ++ i ) {
            C[i][0] = 1;
            for( int j = 1 ; j <= i ; ++ j ) C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
        }
        for( int i = 1 , u , v ; i <= m ; ++ i ) {
            scanf("%lld%lld",&u,&v); G[u].push_back( v );
        }
        for( int i = 1 ; i < ( 1 << n ) ; ++ i)
            for( int j = 1 ; j <= n ; ++ j ) if( i & ( 1 << j - 1 ) )
                    for( int v : G[j] ) if( i & ( 1 << v - 1 ) )
                            ++ d[i];
        for( int i = 1 ; i <= m ; ++ i ) dp[i][0] = 1;
        for( int s = 1 ; s < ( 1 << n ) ; ++ s ) {
            int ps = 0;
            for( int j = 1 ; j <= n ; ++ j ) if( s & ( 1 << j - 1 ) ) ps = j;
            for( int i = 0 ; i <= d[s] ; ++ i ) {
                for( int t = ( s - 1 ) & s ; t != s ; t = ( t - 1 ) & s ) {
                    if( ~t & ( 1 << ps - 1 ) ) continue;
                    for( int j = 0 ; j <= min( d[t] , i ) ; ++ j ) {
                        f[i][s] += dp[j][t] * C[d[s ^ t]][i - j];
                    }
                }
                dp[i][s] = C[d[s]][i] - f[i][s];
            }
        }
        double res = 0.0;
        for( int i = 1 ; i <= m ; ++ i )
            res += 1.0 * i / ( m + 1 ) * ( 1.0 * dp[i][(1<<n) - 1] / C[m][i] - 1.0 * dp[i-1][(1<<n)-1] / C[m][i - 1] );
        printf("%.6lf",res);
    }
    
  • 相关阅读:
    最大子数组问题(分治策略实现)
    Solving the Detached Many-to-Many Problem with the Entity Framework
    Working With Entity Framework Detached Objects
    Attaching detached POCO to EF DbContext
    如何获取qq空间最近访问人列表
    Health Monitoring in ASP.NET 2.0
    problem with displaying the markers on Google maps
    WebMatrix Database.Open… Close() and Dispose()
    Accessing and Updating Data in ASP.NET: Retrieving XML Data with XmlDataSource Control
    Create web setup project that has crystal reports and sql script run manually on client system
  • 原文地址:https://www.cnblogs.com/yijan/p/12323296.html
Copyright © 2011-2022 走看看