• [补题记录] Atcoder Beginner Contest 298(E)


    URL:https://atcoder.jp/contests/abc298

    目录

    E

    Problem/题意

    Thought/思路

    Code/代码


    E

    Problem/题意

    A、B 轮流投色子,A 投出 [1, P] 点数的概率相等,B投出 [1, Q] 点数的概率相等。

    现有 N 个点,初始时,A 位于点 a,B 位于点 b。假设 A 或 B 现在在点 X,每投出一个点数 i,则 A 或 B 会走到 min(X + i, N),先走到 N 的获胜。

    问 A 先投色子,A 赢的概率。

    Thought/思路

    求到某个点的概率题,通常都会需要用到类似:

    dp[i] = 1 / P * (dp[i + A1] + dp[i + A2] + ... + dp[i + Ap])

    这种形式的状态转移方程,意为:我知道了后几个点的期望,可以反推从前面的点出发,然后获胜的期望。

    这道题就是多了一个人,使得状态转移不仅是简单的从后面的转移到前面的,而是需要考虑前一步是由谁来做的,那么就应该从谁哪里转移过来


    dp[i][j][0]:A 在 i,B 在 j,由 A 投色子A 获胜的概率

    dp[i][j][1]:A 在 i,B 在 j,由 B 投色子A 获胜的概率

    dp[i][j][0] 的前一步是由 B 做出的,并且 A 在点 i 的状态,是由前一步的所有 A 可能到的点的状态转移过来的。因此:

    dp[i][j][0] = \frac{1}{p}\sum_{k=1}^{p}dp[min(i + k, N)][j][1]

    同理:

    dp[i][j][1] = \frac{1}{q}\sum_{k=1}^{q}dp[i][min(k + k, N)][0]

    最后输出 打派【a】【b】【0】即可。

    Code/代码

    1. #include "bits/stdc++.h"
    2. #define int long long
    3. const int mod = 998244353;
    4. int n, a, b, p, q, dp[107][107][2];
    5. int ksm(int a, int b) {
    6. int res = 1;
    7. while (b > 0) {
    8. if (b & 1) res = res * a % mod;
    9. a = a * a % mod;
    10. b /= 2;
    11. }
    12. return res % mod;
    13. }
    14. int inv(int a, int p) {
    15. return ksm(a, p - 2);
    16. }
    17. signed main() {
    18. std::cin >> n >> a >> b >> p >> q;
    19. for (int i = 1; i <= n; ++ i) {
    20. dp[n][i][0] = 1; // A 在 N,A 赢的概率肯定是 100%
    21. dp[n][i][1] = 1;
    22. dp[i][n][0] = 0; // B 在 N,A 赢的概率肯定是 0%
    23. dp[i][n][1] = 0;
    24. }
    25. for (int i = n - 1; i >= 1; -- i) {
    26. for (int j = n - 1; j >= 1; -- j) {
    27. for (int k = 1; k <= p; ++ k) { // 这一轮由 A 走,那么 A 赢的概率,需要从上一轮 B 走且 A 走到 min(i + k, n) 且 A 赢的概率转移过来
    28. dp[i][j][0] = (dp[i][j][0] + dp[std::min(i + k, n)][j][1]) % mod;
    29. }
    30. dp[i][j][0] = dp[i][j][0] * inv(p, mod) % mod;
    31. for (int k = 1; k <= q; ++ k) {
    32. dp[i][j][1] = (dp[i][j][1] + dp[i][std::min(j + k, n)][0]) % mod;
    33. }
    34. dp[i][j][1] = dp[i][j][1] * inv(q, mod) % mod;
    35. }
    36. }
    37. std::cout << dp[a][b][0];
    38. }

  • 相关阅读:
    第24集丨人生的智慧:做人之道“成色”比“斤两”更重要
    xml开发方式下AutowiredAnnotationBeanPostProcessor的注册时机
    Python爬虫入门基础学习(一)
    Spring三级缓存解决循环依赖
    java中的集合
    do-exercise-淘宝网店
    shell脚本循环语句
    springboot+shiro+layuimini实现后台管理系统的权限控制(三)利用shiro实现对用户的授权
    windows局域网传文件5种常用方法
    List集合&UML图
  • 原文地址:https://blog.csdn.net/joyride_run/article/details/133633621