期望

期望

定义

如果 X 是离散的随机变量,输出值为 x1,x2,,和输出值的相应的概率为 p1,p2,(概率和为 1)。

E(X)=ipixi

例题

Revenge of "The Salary of AtCoder Inc."

[ABC326E] Revenge of "The Salary of AtCoder Inc."

青木是 AtCoder 公司的一名员工,他本月的工资由整数 N 和长度为 N 的序列 A 决定,具体如下。
首先,给他一个N面的骰子,该骰子以相等的概率显示从1N的整数,以及一个变量x=0

然后,重复以下步骤直到结束。

  • 掷一次骰子,让y成为结果。
    • 如果是x<y,付给他Ay日元,让x=y
    • 否则,终止该过程。

青木这个月的工资就是通过这个过程支付的总额。
求青木本月工资的对 998244353 取模后的结果。

思路:

根据期望的线性,工资的总期望 E 等于序列 A 上的每一个值乘以 p(i),其中 p(i) 表示骰子掷到 i 且有效的概率。

E=piai。而

pi=1nj=0i1pj

其中 1npj 表示在 j 这个点,掷骰子掷到 i 的概率。其中 表示在 j 这个点,掷骰子掷到 i 是一个整体。

可以用前缀和优化计算 O(n).

code:

#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int MAXN = 3e5 + 7;
const int MOD = 998244353;
int n;
int p[MAXN],prep[MAXN],a[MAXN];
int qpow(int a,int x){
	int res = 1;
	while(x){
		if(x & 1) res = res * a % MOD;
		a = a * a % MOD;
		x >>= 1;
	}
	return res;
}
signed main(){
	scanf("%lld", &n);
	for(int i = 1;i <= n;i++) scanf("%lld", &a[i]);
	p[0] = 1,prep[0] = 1;
	for(int i = 1;i <= n;i++){
		p[i] = prep[i - 1] * qpow(n,MOD - 2) % MOD;
		prep[i] = (prep[i - 1] + p[i]) % MOD;
	}
	int ans = 0;
	for(int i = 1;i <= n;i++){
		(ans += (a[i] * p[i])) %= MOD;
	}
	printf("%lld", ans);
	return 0;
}

Coupons

优惠券 Coupons

每张彩票上有一个漂亮图案,图案一共n种,如果你集齐了这n种图案就可以~~~~兑换大奖。

现在请问,在理想(平均)情况下,你买多少张彩票才能获得大奖的?

思路:

dpi 为从第 i 种到 n 种所要经过的期望步数,易知 dpn=0.

则:

dpn1=1ndpn+n1ndpn1+1dpn2=2ndpn1+n2ndpn2+1

我们归纳化简:

dpi=nindpi+1+indpi+1dpi=dpi+1+nnians=i=1nni

循环统计答案即可.

我们分析过程: dpn1=1ndpn+n1ndpn1+1

1ndpn 表示有 1n 的概率拿到未选择过的种类的期望,而 n1n 的概率停在原地不动,而这两个操作都会使期望加 1.

分析结束,式子成立,无代码.

收集邮票

P4550 收集邮票

n 种不同的邮票,皮皮想收集所有种类的邮票。唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是 n 种邮票中的哪一种是等概率的,概率均为 1/n。但是由于凡凡也很喜欢邮票,所以皮皮购买第 k 次邮票需要支付 k 元钱。

现在皮皮手中没有邮票,皮皮想知道自己得到所有种类的邮票需要花费的钱数目的期望。

首先我们设 fi 表示从 i 种邮票收集到 n 种邮票的期望步数

那么易知 fn = 0,且有:

fn1=1nfn+n1nfn1+1fn2=2nfn1+n2nfn2+1

f0=i=1nnifi=fi+1+nni

但是题目中的条件是 购买第k次邮票需要支付k元钱,所以我们需要设 dpi 为从 i 种邮票拿到 n 种的期望钱数,显然 dpn=0,而我们有 in 的概率取到已经取到过的,期望为 in(dpi+fi+1),有 nin 的概率取到没有的,期望为 nin(dpi+1+fi+1+1)

所以:

dpi=in(dpi+fi+1)+nin(dpi+1+fi+1+1)

化简得到:

dpi=dpi+1+1+fi+1+i(1+fi)ni

最后输出 dp[0] 即可。

code:

#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1e4 + 7;
int n;
double f[MAXN];
double dp[MAXN];
int main(){
	scanf("%d", &n);
	for(int i = n - 1;i >= 0;i--) f[i] = f[i + 1] + n * 1.0 / (n - i);
	for(int i = n - 1;i >= 0;i--) dp[i] = dp[i + 1] + 1 + f[i + 1] + i * (1 + f[i]) / (n - i);
	printf("%.2lf", dp[0]);
	return 0;
}

代码超短。

OSU!

P1654 OSU!

一共有 n 次操作,每次操作只有成功与失败之分,成功对应 1,失败对应 0n 次操作对应为 1 个长度为 n 的 01 串。在这个串中连续的 X1 可以贡献 X3 的分数,这 x1 不能被其他连续的 1 所包含(也就是极长的一串 1,具体见样例解释)

现在给出 n,以及每个操作的成功率,请你输出期望分数,输出四舍五入后保留 1 位小数。

我们考虑第 i 位和第 i+1 位,设第 i 位为 1 产生连续的成功操作的长度的期望为 x,则分数期望为 x3。到 i+1 位时,长度的期望变为 (x+1)×pi+1,分数的期望变成 ((x+1)×pi+1)3=pi+13×(x3+3x2+3x+1)

观察式子,我们发现我们需要知道 x,x2,x3 的期望。

则我们设 xi,yi,zi 分别表示 1,2,3 次方的期望,则有:

xi=(xi1+1)×pi

yi=(yi1+2xi1+1)×pi

zi=(zi1+3yi1+3xi1+1)×pi

但是我们的答案不是单独一个点对整个序列产生分数的期望,所以要改一下三次方的式子:

zi=(zi1+3yi1+3xi1+1)×pi+zi1×(ipi)

zi=zi1+(3yi1+3xi1+1)×pi

答案就是 zn

code:

#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 1e5 + 7;
double x1[MAXN],x2[MAXN],x3[MAXN];
int n;
double p[MAXN];
int main(){
	cin >> n;
	for(int i = 1;i <= n;i++) cin >> p[i];
	for(int i = 1;i <= n;i++) x1[i] = (x1[i - 1] + 1) * p[i];
	for(int i = 1;i <= n;i++) x2[i] = (x2[i - 1] + 2 * x1[i - 1] + 1) * p[i];
	for(int i = 1;i <= n;i++) x3[i] = x3[i - 1] + (3 * x2[i - 1] + 3 * x1[i - 1] + 1) * p[i];
	printf("%.1lf", x3[n]);
	return 0;
}

P8774 爬树的甲壳虫

P8774 [蓝桥杯 2022 省 A] 爬树的甲壳虫

有一只甲壳虫想要爬上一颗高度为 n 的树,它一开始位于树根, 高度为 0,当它尝试从高度 i1 爬到高度为 i 的位置时有 Pi 的概率会掉回树根, 求它从树根爬到树顶时, 经过的时间的期望值是多少。

做法一:

fi 是从 0 爬到 i 处经过的期望时间,那么不管怎么样,都要从 fi1 转移过来,且有 pi 的概率是 先回树根,花费1的时间,然后花费f[i]时间回到i节点 时间为 fi+1,有 1pi 的概率不掉,时间为 1

那么:

fi=fi1+(1pi)+pi×(fi+1)

化简得:

fi=(1+fi1)1pi

code:

#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int MAXN = 1e5 + 7;
const int MOD = 998244353;
int n,x[MAXN],y[MAXN];
int f[MAXN];
int qpow(int a,int x){
	int res = 1;
	while(x){
		if(x & 1) res = res * a % MOD;
		a = a * a % MOD;
		x >>= 1;
	}
	return res;
}
signed main(){
	cin >> n;
	for(int i = 1;i <= n;i++) cin >> x[i] >> y[i];
	for(int i = 1;i <= n;i++){
		f[i] = (f[i - 1] + 1) * y[i] % MOD * qpow(y[i] - x[i],MOD - 2) % MOD;
		f[i] %= MOD;
	}
	cout << f[n];
	return 0;
}
posted @   wyl123ly  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示