期望DP——解决从自身转移的情况

期望DP——解决从自身转移的情况

问题背景

可以进行若干次抽奖,每一次分别获得 0k 个物品的概率 pj 都是确定的,给定一个 X ,求抽到 X 个物品的期望抽奖次数。

如果定义 fi 为获得 i 个物品的期望次数,那么这个转移方程也是十分显然:

fi=1+j=0kfij×pj

出现的问题

从数学意义上思考,这个式子本身是没有问题的。

但是从程序的方面来思考,我们写一个 naive 的转移肯定是行不通的,因为这涉及到当 j=0 的时候 ,fi 会从自身转移。

解决方法

可以通过解方程的方法来从数学的角度变形这个式子:

fi=1+fi×p0+j=1kfij×pj

再化简一下可以得到:

fi=1+j=1kfij×pj1p0

这个时候就可以发现转移方程里面不包含 fi 本身了,可以直接转移。

例题

abc382_e

这个题并没有直接给出 p ,而是给出了 n 个相互独立的概率 ,所以开一个卡包获得 0n 张卡的概率需要自己算。

这个题里面我们还需要人为处理一下 p ,这个也考虑从 DP 的角度来解决,定义 gi,j 数组为考虑了前 i 张卡获得了 j 张卡的概率,这样的话转移还是就挺明显的 :

gi,j=gi1,j×(1pi)+gi1,j1×pi

然后剩下的就直接套上面的流程即可。

Code

#include<bits/stdc++.h>
using namespace std;
const int N=5010;
double f[N],g[N][N];
int n,x;
double p[N];
int main()
{
cin>>n>>x;
for(int i=1;i<=n;++i)scanf("%lf",&p[i]),p[i]/=100.0;
g[0][0]=1;
for(int i=1;i<=n;++i)
{
g[i][0]=g[i-1][0]*(1-p[i]);
for(int j=1;j<=i;++j)
g[i][j]=g[i-1][j-1]*p[i]+g[i-1][j]*(1-p[i]);
}
f[0]=0;
for(int i=1;i<=x;++i)
{
f[i]=1;
for(int j=max(0,i-n);j<i;++j)
{
f[i]+=f[j]*g[n][i-j];
}
f[i]/=(1-g[n][0]);
}
printf("%.16lf",f[x]);
return 0;
}

abc314_e

类似于完全背包,有 n 个不同的卡包,每一个都可以选择无限次

Code

abc342_f

题意

这个题严格意义上来讲其实并没有涉及到从自身转移的情况,但是属于是比较难的一道期望DP,而且还是比较典型。

题意就是你可以先抛若干次骰子,每次都可以等概率地获得 1D 的点数,记最后你获得的点数为 x 。紧接着另外一个人也丢若干骰子,他的投掷过程和你的完全独立,直到他获得至少 L 分之前,他都不会停止,记最后他获得的分数是 y

给定一个分数上界 N

如果最后你的点数 x 大于 N , 那么你就输了。

否则:

  • 如果 y>N 或者 x>y ,就可以获胜。
  • 否则就失败。

现在询问按照最优策略行事,最后获胜的概率多少?

分析

这是一个类博弈问题,我们尝试定义 dpi 为:从总计得到 i 点数之后进行操作获得的最大获胜概率,那么这时候就有两种决策:

  1. 再投一次骰子。
  2. 不投了。

对于情况 1 ,可以转化为子问题求解。

也就是

j=i+1i+DdpjD

对于情况 2 ,这时候我们就要对于确定的 x ,来看看 y 的概率分布,从而确定获胜情况。

由于两个过程是相互独立的,所以我们可以预处理出 y 最后停在任意一点的概率,实际问题的意义上考虑,y 最后所在的位置肯定只能是 [L,L+D1] 的区间内,我们定义 g 数组为所求的数组,发现 g 数组的每一个 gi 会以 1D等概率转移给他之后 [1,D]gj ,那么这个区间加的过程实际上可以通过差分、树状数组、线段树的方式来优化,这里选择的是差分。

由于我们正序枚举 y 可能的位置,所以只会对后面的产生加减,那么一边枚举一边对差分数组进行前缀和 ,可以同时得到当前位置的概率。并且我们在 iL 的时候就会停止前进,那么只需要枚举 [0,L1]i 即可。

考虑对于一个给定的 x ,去计算 y 对应的能使之获胜的概率,显然就是 ansx=1i=LNgi+i=Lx1gi ,如果 L>x1 的话那么最后一项对应是 0 。这个显然可以通过前缀和进行优化。

最后的转移方程就是

dpi=max(j=i+1i+DdpjD,ansx)

其中 DP 的区间和可以通过双指针的思想O(1)求出。

Code

abc333_f

posted @   Hanggoash  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
动态线条
动态线条end
点击右上角即可分享
微信分享提示