题解 | 小红叒战小紫

小红叒战小紫

https://www.nowcoder.com/practice/4b6be52dc6814a5f80119e8b22624128

#include <bits/stdc++.h>
const int mod = 1E9 + 7;
using namespace std;
 
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n, m;
    int a = 0, b = 0;
 
    int w;
 
    std::cin >> n >> m;
    for (int i = 0; i < n; ++i) std::cin >> w, a += w == 1;
    for (int i = 0; i < m; ++i) std::cin >> w, b += w == 1;
    int  c = n - a, d = m - b;
 
    std::function<int(int)> get_inv = [](int v)->int {
        int p = mod - 2;
        int inv = 1;
        while (p) {
            if (p & 1) inv = 1ll * inv * v  % mod;
            v = 1ll * v * v % mod;
            p >>= 1;
        }
        return inv;
    };
 
    int dp[51][51];
    dp[0][0] = dp[a][b] = 0;
 
    if (a != n || b != m) {
        for (int i = 1; i <= a; ++i) {
            int inv = get_inv(i);
            dp[i][0] = (1 + 1ll * c * inv % mod + dp[i - 1][0]) % mod;
        }
 
        for (int i = 1; i <= b; ++i) {
            int inv = get_inv(i);
            dp[0][i] = (1 + 1ll * d * inv % mod + dp[0][i - 1]) % mod;
        }
 
        for (int i = 1; i <= a; ++i) {
            for (int j = 1; j <= b; ++j) {
                int inv = get_inv(i * d + j * c);
                dp[i][j] = 1ll * inv * (((i + c) * (j + d) + 1ll * i * d * dp[i - 1][j] % mod) % mod + 1ll * c * j * dp[i][j - 1] % mod) % mod;
            }
        }
    }
    std::cout << dp[a][b];
    return 0;
}

————————————————————————————————————————————————————————————————
期望Dp,显然这是个马尔科夫过程,对于每一次的选择,不影响下一次的双方选牌,使用条件概率求解期望即可。注意到当双方有一方全为0时连比都不用比,直接输出即可。由于期望值里边有个分式还要要取模,涉及一个逆元求解问题,手玩了下发现这个逆元比较大,不要用线性递推直接用费马小定理求。

全部评论

相关推荐

03-27 17:33
门头沟学院 Java
代码飞升:同学院本,你要注意hr当天有没有回复过,早上投,还要打招呼要推销自己,不要一个劲投
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务