BZOJ4008 : [HNOI2015]亚瑟王(期望dp)

题意

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

题解

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

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

发现有句神奇的话

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

这个是 __debug 曾说的一句话

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

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

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

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

dpi,j=dpi+1,j×(1pi)j+(dpi+1,j1+di)(1(1pi)j)

考虑分两种

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

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

最后答案就是 dp1,r 了。

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

时间复杂度 Θ(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\n", dp[1][r]); } return 0; }

__EOF__

本文作者zjp_shadow
本文链接https://www.cnblogs.com/zjp-shadow/p/8620065.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zjp_shadow  阅读(192)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示