【期望】【DP】数学期望总结(ing)

题目概览
LightOJ - 1027 A Dangerous Maze
LightOJ - 1030 Discovering Gold:概率dp
LightOJ - 1038 Race to 1 Again:统计因子的贡献
LightOJ - 1248 Dice (III) :概率dp 或 几何分布
LightOJ - 1265 Island of Survival:简单O(1)题

前置技能

  1. 期望可以分解成多个子期望的加权和,权为子期望发生的概率,即 E ( a A + b B + . . . ) = a E ( A ) + b E ( B ) + . . . + 1 E(aA + bB+...) = aE(A) + bE(B) + ... + 1 E(aA+bB+...)=aE(A)+bE(B)+...+1

LightOJ - 1027 A Dangerous Maze

题目链接

Description

在n个门前选择一扇门出去, 如果第i扇门的 Xi 为正,会在 Xi 时间后离开迷宫,否则会在 |Xi| 后回到初始地方,并且忘记了刚才的选择, 选择每扇门等概率的。计算离开的期望。

Solution

定义一次选择到正数的概率为P1,选择了正数后离开的平均时间为T1,选择到负数的概率是P2, 选择了负数后回到初始位置的平均时间为T2。设离开的期望为Y。
Y = P 1 ∗ T 1 + P 2 ∗ ( T 2 + Y ) Y = P1 * T1 + P2 * (T2 + Y) Y=P1T1+P2(T2+Y)
Y = P 1 ∗ T 1 + P 2 ∗ T 2 P 1 Y = \frac{P1*T1 + P2*T2}{P1} Y=P1P1T1+P2T2
经过整理 Y = ∑ i = 1 N a b s ( X i ) 正 数 的 个 数 Y=\frac{\sum _{i = 1} ^{N} abs(Xi)}{正数的个数} Y=i=1Nabs(Xi)
最后对答案取个gcd即可。

Code

#include <cstdio>

#define rush() int T;scanf("%d", &T);for(int cas = 1; cas <= T; cas++)

int main()
{
   
	rush() {
   
		int n; 
		scanf("%d", &n);
		int cnt = 0, sum = 0, x;
		for(int i = 1; i <= n; i++) {
   
			scanf("%d", &x);
			sum += abs(x);
			if(x > 0) cnt++;
		}
		int g = __gcd(sum, cnt);
		printf("Case %d: ", cas);
		if(cnt == 0) printf("inf\n");
		else printf("%d/%d\n", sum/g, cnt/g);
	}
	return 0;
}

LightOJ - 1030 Discovering Gold

题目链接

Description

n个点,每个点有一些金子。从点1开始,每次扔一次6面骰子,向前走点数步,并且拿走那个点的金子,如果当前位置加扔出的点数大于n,就重新扔。询问走到n时,取走的金子的期望。

Solution

方案一:从前到后递推
假设 dp[i] 为到第i个点的概率,a[i]为第i个格子的金子数量。那么期望就是 ∑ d p [ i ] ∗ a [ i ] \sum dp[i] * a[i] dp[i]a[i]
对于初始点1来说,dp[1] = 1,否则,dp[i] = dp[j] * 骰子摇出点数为 j-i 的概率

方案二:从后到前倒退
那么当前的状态等于 所有后继状态的期望 * 到达它的概率 进行求和。

由于走到的点是一定能拿到的,因此令每个的点的初始期望值等于每个点的初始值,即:dp[i] = a[i].

则:

  • 在第 n 个点,获得的金子数目为 dp[n]
  • 在第 n-1 个点,掷骰子有一种情况,获得的数目为: dp[n-1] + dp[n]
  • 在第 n-2 个点,掷骰子有两种情况,获得的数目为: dp[n-2] + dp[(n-2)+1]/2 + dp[(n-2)+2]/2
  • 在第 i 个点,掷骰子有六种情况,获得的数目为: dp[i] = dp[i] + dp[i+1]/6 + dp[i+2]/6 + dp[i+3]/6 + dp[i+1]/6 + dp[i+5]/6 + dp[i+6]/6

如上进行逆推,最后得到的 f[1] 就是最终的期望值

Code

方案一:

#include <cstdio>
#define rush() int T;scanf("%d", &T);for(int cas = 1; cas <= T; cas++)

double a[105];
double dp[105], cnt[105];

int main()
{
   
	rush() {
   
		printf("Case %d: ", cas);
		int n; 
		scanf("%d", &n);
		for(int i = 1; i <= n; i++) 
			scanf("%lf", a + i);
			dp[i] = 0;
		}
		dp[1] = 1.0;
		double ans = 0.0;
		for(int i = 1; i <= n; i++) 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值