• bzoj4008: [HNOI2015]亚瑟王【期望dp】


      一个特别神奇的dp,特别厉害。

      f(i, j) 表示 有 j 轮发动技能的牌在 [1, i] 另外的m - j轮在[i + 1, n]之间的概率。

      怎么转移呢?

      首先考虑i这张牌不选的情况,f(i - 1, j) 表示 j --> [1, i - 1] && m - j --> [i, n]        (用箭头表示在[]之间...),那么我们只需要让在[i, n]之间的m - j个选择都不是i即可,那么我们应该 * (1 - p[i]) ^ (m - j)

      再考虑这张牌我们要选的情况,f(i - 1, j - 1)表示 j - 1 --> [1, i - 1] && m - j + 1 --> [i, n], 那么我们需要m - j + 1中至少有一个i, 所以我们应该 * (1 - (1 - p[i]) ^ (m - j + 1))

      所以就有了转移方程:

    $mbox{f(i, j) = f(i - 1, j) * (1 - p[i]) ^ {m - j} + f(i - 1, j - 1) * (1 - (1 - p[i]) ^ {m - j + 1})}$

      那么初始条件是多少呢? f(0, 0) == 1 为什么呢:

      m次选择都在n之间的概率为1,那么f(n, m) == 1,这意味着m --> [1, n] 那么 另外的 0个选择--> 0,所以f(0, 0) == 1.

      那么答案是多少呢?

      应该是对于每一个扑克牌,我们扫描整个m轮,用当前的概率与扑克牌的贡献的成绩累加答案。

      ans += d[i] * f[i - 1][j] * (1 - pow(1 - p[i], m - j)); 用j --> [1, i - 1] && m - j --> [i, n] 并且m - j中至少有一个i。

     1 #include <bits/stdc++.h>
     2 #define rep(i, a, b) for (int i = a; i <= b; i++)
     3 #define drep(i, a, b) for (int i = a; i >= b; i--)
     4 #define REP(i, a, b) for (int i = a; i < b; i++)
     5 #define mp make_pair
     6 #define pb push_back
     7 #define clr(x) memset(x, 0, sizeof(x))
     8 #define xx first
     9 #define yy second
    10 using namespace std;
    11 typedef long long i64;
    12 typedef pair<int, int> pii;
    13 const int inf = ~0U >> 1;
    14 const i64 INF = ~0ULL >> 1;
    15 //***********************************
    16 
    17 long double p[225]; int d[225];
    18 long double f[225][135];
    19 
    20 int main() {
    21     int T; scanf("%d", &T);
    22     while (T--) {
    23         int n, m;
    24         scanf("%d%d", &n, &m);
    25         rep(i, 1, n) scanf("%Lf%d", &p[i], &d[i]);
    26         memset(f, 0, sizeof(f));
    27         f[0][0] = 1;
    28         rep(i, 1, n) {
    29             rep(j, 0, m) f[i][j] = f[i - 1][j] * pow(1 - p[i], m - j) + f[i - 1][j - 1] * (1 - pow(1 - p[i], m - j + 1));
    30         }
    31         long double ans(0);
    32         rep(i, 1, n) {
    33             rep(j, 0, m) {
    34                 ans += d[i] * f[i - 1][j] * (1 - pow(1 - p[i], m - j));
    35             }
    36         }
    37         printf("%.10Lf
    ", ans);
    38     }
    39     return 0;
    40 }
    View Code

      有一点还不太理解,就是在转移的时候,假如我们选取了i,那么用f(i - 1, j - 1)转移的时候乘的是至少有一个i的概率,那假如大于1个那么和题意不就矛盾了吗。。求助。。。

  • 相关阅读:
    Discuz热搜在哪里设置?
    Discuz如何设置帖子隐藏回复可见或部分可见方法
    新版Discuz!应用中心接入教程(转)
    Diszuz管理面版被锁怎么办?
    vs 2019 调试无法查看变量
    Google Docs 的格式刷快捷键
    chrome 的常用快捷键
    Activiti 数据库表结构
    activiti 报 next dbid
    尚硅谷Java基础_Day2
  • 原文地址:https://www.cnblogs.com/y7070/p/5090155.html
Copyright © 2020-2023  润新知