zoukankan      html  css  js  c++  java
  • 「CF708E」Student's Camp

    传送门
    首先分析题意,存在两个联通分量等价于第 (0) 行和第 (n + 1) 行不连通。
    然后我们可以发现这个风只会吹每一行的端点,也就是说每一行总是一段连续的区间。
    那么不连通的情况就是存在相邻两行的区间不交。
    那么首先考虑一个很显然的暴力:
    (dp_{i, l, r}) 表示前 (i) 行联通,第 (i) 行的区间为 ([l, r]) 的概率。
    我们设 (q_i = {k choose i}p^i(1 - p) ^ {k - i}) ,表示所有 (k) 次吹风中,有 (i) 次成功吹走砖块的概率。
    那么某一行是 ([l, r]) 的概率就是 (P(l, r) = q_{l - 1} imes q_{m - r})
    所以有 (dp_{i, l, r} = P(l, r) sum dp_{i - 1, l ^ prime, r ^ prime}, [l ^ prime, r ^ prime] cap [l, r] e varnothing)
    初始化 (dp_{0, 1, m} = 1),此时最后的答案就是 (sum dp_{n, l, r})
    然后我们考虑优化。
    我们可以改写一下上面那个 (dp) 方程:

    [egin{aligned} dp_{i, l, r} & = P(l, r) sum dp_{i - 1, l ^ prime, r ^ prime}, [l ^ prime, r ^ prime] cap [l, r] e varnothing \ & = P(l, r) left( sum_{l ^ prime < r ^ prime} dp_{i - 1, l ^ prime,r ^ prime} - sum_{r ^ prime < l} dp_{i - 1, l ^ prime, r ^ prime} - sum_{r < l ^ prime} dp_{i - 1, l ^ prime, r ^ prime} ight) end{aligned} ]

    写成这样后,我们可以想到用前缀和来优化转移:
    (F_{i, r} = sum_{l le r} dp_{i, l, r}, S_{i, r} = sum_{j le r} F_{i, j})
    考虑到左右的对称性,我们也可以用这两个东西算后缀形式的和。
    那么我们上面那个式子就可以进一步写成:

    [dp_{i, l, r} = P(l, r) left( S_{i - 1, m} - S_{i - 1, l - 1} - S_{i - 1, m - r} ight) ]

    那么就可以推出:

    [egin{aligned} F_{i, r} & = sum_{l le r} dp_{i, l, r} \ & = sum_{l le r} P(l, r) left( S_{i - 1, m} - S_{i - 1, l - 1} - S_{i - 1, m - r} ight) \ & = sum_{l le r} q_{l - 1} imes q_{m -r} left( S_{i - 1, m} - S_{i - 1, l - 1} - S_{i - 1, m - r} ight) \ & = q_{m - r} left[ sum_{l le r} q_{l - 1} left( S_{i - 1, m} - S_{i - 1, l - 1} ight) - S_{i - 1, m - r} sum_{l le r} q_{l - 1} ight] end{aligned} ]

    不难看出其中的前缀和优化,那么我们就可以算出 (F(i, r))(S(i, r)) 了。
    最后的答案就是 (S_{n, m})
    参考代码:

    #include <cstdio>
    
    const int _ = 1502, __ = 1e5 + 5, mod = 1e9 + 7;
    
    int n, m, k, a, b, P, fac[__], ifc[__], p[__];
    int dp[_][_], s[_][_], s1[_], s2[_];
    
    int power(int x, int k) {
        int res = 1;
        for (; k; k >>= 1, x = 1ll * x * x % mod)
            if (k & 1) res = 1ll * res * x % mod;
        return res % mod;
    }
    
    int C(int N, int M) { return 1ll * fac[N] * ifc[M] % mod * ifc[N - M] % mod; }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("cpp.in", "r", stdin), freopen("cpp.out", "w", stdout);
    #endif
        scanf("%d%d%d%d%d", &n, &m, &a, &b, &k);
        P = 1ll * a * power(b, mod - 2) % mod;
        fac[0] = ifc[0] = 1;
        for (int i = 1; i <= k; ++i) fac[i] = 1ll * i * fac[i - 1] % mod;
        ifc[k] = power(fac[k], mod - 2);
        for (int i = k; i; --i) ifc[i - 1] = 1ll * i * ifc[i] % mod;
        for (int i = 0; i <= k; ++i)
            p[i] = 1ll * C(k, i) * power(P, i) % mod * power((1 - P + mod) % mod, k - i) % mod;
        dp[0][m] = s[0][m] = 1;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                s1[j] = (s1[j - 1] + 1ll * (s[i - 1][m] - s[i - 1][j - 1] + mod) % mod * p[j - 1] % mod) % mod;
                s2[j] = (s2[j - 1] + p[j - 1]) % mod;
            }
            for (int j = 1; j <= m; ++j) {
                dp[i][j] = 1ll * (s1[j] - 1ll * s[i - 1][m - j] * s2[j] % mod + mod) % mod * p[m - j] % mod;
                s[i][j] = (s[i][j - 1] + dp[i][j]) % mod;
            }
        }
        printf("%d
    ", s[n][m]);
        return 0;
    }
    
  • 相关阅读:
    Swift
    Swift
    Swift
    Swift
    获取项目版本号与设置引导页的判断条件
    [iOS]简单的APP引导页的实现 (Swift)
    iOS
    文顶顶 iOS开发UI篇—UITabBarController简单介绍 iOS开发UI篇—UITabBarController简单介绍
    Swift开源项目精选
    Fuel 5.1安装openstack I版本号环境
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/12858592.html
Copyright © 2011-2022 走看看