期望好题,可以帮助我更加深入地了解期望。

由于 \(k\) 种装备相同,所以只要计算卖掉一种装备得到的金币期望乘以 \(k\) 就行了。

为了避免讨论当前状态的概率,期望 DP 通常采用逆推的方式。

\(f_{i,j}\) 表示从当前打了 \(i\) 只怪兽,这种装备等级为 \(j\) 这个状态开始,最终获得金币的期望。

分类讨论贡献。

  • \(\dfrac {k-1}k\) 的概率抽不到这种装备。这个时候直接从 \(f_{i+1,j}\) 继承,贡献为 \(\dfrac {(k-1)f_{i+1,j}}k\)
  • \(\dfrac j{(j+1)k}\) 的概率抽到等级不超过当前装备的同种装备,此时的贡献为 \(\dfrac {\sum_{l=1}^jf_{i+1,j}+l}{(j+1)k}=\dfrac {jf_{i+1,j}+\frac 12 j(j+1)}{(j+1)k}\)
  • \(\dfrac 1{(j+1)k}\) 的概率抽到等级为 \(j+1\) 的同种装备,此时的贡献为 \(\dfrac {f_{i+1,j+1}+j}{(j+1)k}\)

综上,可以得出状态转移方程:

\[\begin{aligned} f_{i,j}&=\dfrac {(k-1)f_{i+1,j}}k+\dfrac {jf_{i+1,j}+\frac 12 j(j+1)}{(j+1)k}+\dfrac {f_{i+1,j+1}+j}{(j+1)k}\\ &=\dfrac{2(k-1)f_{i+1,j}}{2k}+\dfrac {2jf_{i+1,j}}{2(j+1)k}+\dfrac{j}{2k}+\dfrac {2f_{i+1,j+1}+2j}{2(j+1)k}\\ &=\frac{2(j+1)(k-1)f_{i+1,j}+2jf_{i+1,j}+j(j+3)+2f_{i+1,j+1}}{2(j+1)k}\\ &=\frac{2(kj+k-1)f_{i+1,j}+j(j+3)+2f_{i+1,j+1}}{2(j+1)k} \end{aligned} \]

发现状态是 \(\mathcal O(n^2)\) 的。怎么办呢?

我们发现如果 \(j\) 取到比较大的值时,概率是很小的。由于题目要求使用浮点数而非取模,我们可以在允许的精度范围内损失一些。所以我们为 \(j\) 设置一个上限 \(M\),舍弃后面的状态。上限越大,精度损失越小。

具体分析一下,从 \(j\) 级升到 \(j+1\) 级概率为 \(\dfrac 1{(j+1)k}\),所以期望还要打 \((j+1)k\) 个怪兽才能从 \(j\) 级升到 \(j+1\) 级。则这个装备升级到 \(t\) 的期望次数为 \(\sum_{j=2}^tjk=\dfrac k2(t+2)(t-1)\)。若这个值不超过 \(n\),则 \(t\) 的上界约为 \(500\)。我们取上界 \(M=800\) 就差不多了。

时间复杂度为 \(\mathcal O(nM)\)。本来以为不开滚动数组也能过,没想到还是 MLE 了。

不过开了滚动数组代码依然很短:

#include<cstdio>
using namespace std;
typedef double ld;
const int N=1e5+5,M=800;
int n,k;ld f[2][M+5];
int main(){
	scanf("%d%d",&n,&k);
	for(int i=n;i>=1;i--)for(int j=1;j<=M;j++){
		f[i&1][j]=(2*(k*j+k-1)*f[(i&1)^1][j]+j*(j+3)+2*f[(i&1)^1][j+1])/(2.0*(j+1)*k);
	}
	printf("%.10lf\n",f[1][1]*k);
	return 0;
}

原文地址:http://www.cnblogs.com/hihihi198/p/16882095.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性