zoukankan      html  css  js  c++  java
  • BZOJ4008 : [HNOI2015]亚瑟王(期望dp)

    题意

    略(看了20min才看懂。。。)

    题解

    我一开始天真地一轮轮推期望,发现根本不好算。。。

    唉~ 不会做就只能抄题解咯 看了一波DOFY大佬的解法qwq

    发现有句神奇的话

    记住,期望要倒着推。。。

    这个是 __debug 曾说的一句话

    概率要顺着推,期望要倒着推。

    似乎看上去很有道理 运用到这道题上就很优秀了。

    我们考虑 (dp_{i,j}) 为考虑到 (i) 张卡牌(其中 (i+1 hicksim n),已经考虑完了)并且玩完 (j) 轮的期望伤害。

    然后有个显然 奇妙的dp方程咯(很神)

    [dp_{i,j}=dp_{i+1,j} imes (1-p_i)^j+(dp_{i+1,j-1}+d_i)*(1-(1-p_i)^j) ]

    考虑分两种

    1. 对于卡牌 (i) ,到 (j) 次还没有发动的概率为 ((1-p_i)^j) 。那么我们可以直接可以乘上后一个的也在第 (j) 轮的期望就行了。
    2. (j) 次发动的概率就为 (1-(1-p_i)^j) 。那么后一个就在前一轮((j-1) 轮)了,也乘上那个期望。

    不难发现,逆推 (i) 的话,该算的概率全都会算上,而且不会算错。(因为前面会乘上那个概率来修改后面计算的贡献)

    最后答案就是 (dp_{1,r}) 了。

    这样比网上很多递推然后用概率乘系数的要优秀许多了qwq

    时间复杂度 (Theta(Tnr))

    代码

      #include <bits/stdc++.h>
      #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
      #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
      #define Set(a, v) memset(a, v, sizeof(a))
      using namespace std;
    
      const int N = 1010;
      double p[N], d[N], dp[N][N];
      int n, r, cases;
    
      int main () {
      	scanf("%d", &cases);
      	while (cases --) {
      		scanf ("%d%d", &n, &r);
      		For (i, 1, n)
      			scanf("%lf%lf", &p[i], &d[i]);
      		Fordown (i, n, 1) {
      			double P = 1.00 - p[i];
      			For (j, 1, r) {
      				dp[i][j] = dp[i + 1][j] * P + (dp[i + 1][j - 1] + d[i]) * (1 - P);
      				P *= (1.00 - p[i]);
      			}
      		}
      		printf ("%.10lf
    ", dp[1][r]);
      	}
          return 0;
      }
    
  • 相关阅读:
    Java最近版本新特性使用介绍
    Android开发指南-框架主题-安全和许可
    Android启动组件的三种主流及若干非主流方式
    Android自定义权限和使用权限
    Android 安全架构及权限控制机制剖析
    物联网操作系统Hello China V1.76(PC串口版)版本发布
    android 点九PNG技术 适应不同分辨率 完美显示效果
    mysl lock table read
    mysl lock table read
    mysql DBI 事务控制
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/8620065.html
Copyright © 2011-2022 走看看