什么是期望

当我们在做一些题目的时候可能会 balablabla 一堆,然后问你 XXX 的期望,这个时候像我这种连期望定义都不知道的人就傻了,所以先来了解一下定义是什么。

我们现在有一个变量 \(x\) 和一个序列 \(a\),其中值为 \(a_{i}\) 的数可能不只有一个,\(x\) 的取值可能为 \(a_{1}\)\(a_{n}\) 中任意一个数的值,我们用 \(P(A)\) 来表示 \(x\) 能取到值为 \(A\) 的概率;如果 \(A\) 在序列 \(a\) 中出现的次数为 \(m\),则 \(P(A)=\frac{m}{n}\),对序列 \(a\) 进行去重得到序列 \(b\),元素个数为 \(k\),则 \(x\) 取值的期望为 $$\sum_{i=1}^{k} P(b_{i})\times b_{i} $$

比如说,你掷一个六面的骰子,朝上的点数的期望就是 $$1\times \frac{1}{6}+2\times \frac{1}{6}+3\times \frac{1}{6}+4\times \frac{1}{6}+5\times \frac{1}{6}+6\times \frac{1}{6}=\frac{7}{2}$$

引入

看完上面的内容,应该对于期望有了一定的了解了,我们不妨来举一个简单的例子。

在一个游戏里面,你的人物基础的攻击力为 \(1500\),暴击率为 \(37\%\),暴击伤害翻倍。

那么就是说你每次的攻击都有 \(\frac{37}{100}\) 的概率会造成 \(3000\) 的伤害,\(\frac{63}{100}\) 的概率是造成 \(1500\) 的伤害。

那么你每次攻击所造成的伤害值期望为 $$\frac{37}{100}\times 3000+\frac{63}{100}\times 1500=2055$$

或者再看另一个例子。

有一个商场开设了一个活动,每一个用户可以转动两个转盘来获取奖金,如下图:

期望入门-小白菜博客
image

技术问题凑合看

一个人可以重复获奖,每人第一个转盘可以转两次,第二个转盘可以转三次

第一个转盘获奖的概率为 \(\frac{1}{7}\),第二个转盘获奖的概率为 \(\frac{1}{9}\)

那么我们可以得到每个用户得到的奖金的期望为

\[\frac{1}{7}\times 100\times 2+\frac{1}{9}\times 150\times 3=78.5714
\]

(因为除不尽所以保留了四位小数)

例题

P3802 小魔女帕琪

设魔法的总数为 \(tot\),每一个魔法的个数为 \(a_{1}\)\(a_{7}\)

先考虑当拿了前七个刚好为 \(1,2,3,4,5,6,7\) 放了一次大的情况,概率为:

\[\frac{a_{1}}{tot}\times \frac{a_{2}}{tot-1}\times \frac{a_{3}}{tot-2}\times \frac{a_{4}}{tot-3}\times \frac{a_{5}}{tot-4}\times \frac{a_{6}}{tot-5}\times \frac{a_{7}}{tot-6}
\]

也就是

\[\frac{a_{1}\times a_{2}\times a_{3}\times a_{4}\times a_{5}\times a_{6}\times a_{7}}{tot\times (tot-1)\times (tot-2)\times (tot-3)\times (tot-4)\times (tot-5)\times (tot-6)}
\]

那么我们先取哪一种的顺序的没有关系的,只要前七个的魔法是不同的,那么触发的概率就是上面的柿子。

所以我们前七个放出大招的可能就是这个固定的值,而可能性就是这七个魔法的全排列个数也就是 \(7!\),所以我们前七个能放出来大招的期望就是

\[\frac{7!\times a_{1}\times a_{2}\times a_{3}\times a_{4}\times a_{5}\times a_{6}\times a_{7}}{tot\times (tot-1)\times (tot-2)\times (tot-3)\times (tot-4)\times (tot-5)\times (tot-6)}
\]

而我们的总长度为 \(tot\),也就是说有 \(tot-6\) 个的七个连续的魔法,所以答案还要再乘以 \(tot-6\),所以最终答案为

\[\frac{7!\times a_{1}\times a_{2}\times a_{3}\times a_{4}\times a_{5}\times a_{6}\times a_{7}}{tot\times (tot-1)\times (tot-2)\times (tot-3)\times (tot-4)\times (tot-5)}
\]

code:

#include<bits/stdc++.h>
#define N 10100
using namespace std;
double a[N],tot,ans=1;
signed main()
{
	for(int i=1;i<=7;i++)
	{
		cin>>a[i];
		tot+=a[i];
		if(a[i]==0)
		{
			cout<<"0.000"<<endl;
			return 0;
		}
	}
	for(int i=1;i<=6;i++)
		ans=ans*a[i]/(tot+1-i)*i;
	ans*=a[7]*7.0;
	printf("%.3lf\n",ans);
	return 0;
}

P1297 [国家集训队]单选错位

这道题目我们需要分类讨论一下。

  1. 当前的 \(a_{i}=a_{i+1}\),那么这个时候第 \(i\) 道题目做对的概率就是 \(\frac{1}{a_{i}}=\frac{1}{a_{i+1}}\)

  2. 当前的 \(a_{i}>a_{i+1}\),那么这时我们的答案是 \(1\)\(a_{i}\) 的,而实际上 \(a_{i+1}\)\(a_{i}\) 的答案是不可能正确的,所以我们的答案在正确答案范围中的概率为 \(\frac{a_{i+1}}{a_{i}}\),所以答案正确的概率为 \(\frac{a_{i+1}}{a_{i}}\times \frac{1}{a_{i+1}}=\frac{1}{a_{i}}\)

  3. 当前的 \(a_{i}<a_{i+1}\),那么这时我们的答案是 \(1\)\(a_{i}\)的,实际上 \(a_{i}\)\(a_{i+1}\) 的答案是不可能取到的,如果正确答案在这个区间那我们也没办法,我们能随机到正确答案的概率就是 \(\frac{a_{i+1}}{a_{i}}\),那我们的答案正确的概率为 \(\frac{a_{i}}{a_{i+1}}\times \frac{1}{a_{i}}=\frac{1}{a_{i}}\)

所以除第 \(n\) 个外的题目做对的期望为 \(\frac{1}{\max(a_{i+1},a_{i})}\)

最终答案为

\[\sum_{i=1}^{n} \frac{1}{\max(a_{i+1},a_{i})}
\]

code:

#include<bits/stdc++.h>
#define N 10001000
using namespace std;
int n,a[N],A,B,C;
inline void init()
{
    scanf("%d%d%d%d%d",&n,&A,&B,&C,a+1);
	for(int i=2;i<=n;i++)a[i]=((long long)a[i-1]*A+B)%100000001;
	for(int i=1;i<=n;i++)a[i]=a[i]%C+1;
}
signed main()
{
	init();
	double ans=0;
	for(int i=1;i<=n-1;i++)ans+=1.0/max(a[i],a[i+1]);
	ans+=1.0/max(a[1],a[n]);
	printf("%.3lf\n",ans);
	return 0;
}

FAVDICE - Favorite Dice

我们设 \(f[i]\) 表示当前已经掷到了 \(i\) 个面还需要的次数。

那么我们有 \(\frac{i}{n}\) 的概率是掷到已经掷到过的面,所以还需要掷 \(f[i]\) 次。

\(1-\frac{i}{n}\) 的概率掷到没有掷到过的面,所以还需要掷 \(f[i+1]\) 次。

由于我们掷了这一次,所以无论结果是什么,都是要加一,所以得出转移方程

\[f[i]=\frac{i}{n}\times f[i]+\frac{n-i}{n}\times f[i+1]+1
\]

合并同类项后得

\[\frac{n-i}{n}\times f[i]=\frac{n-i}{n}\times f[i+1]+1
\]

通分得

\[f[i]=f[i+1]+\frac{n}{n-i}
\]

code:

#include<bits/stdc++.h>
#define N 1000100
using namespace std;
int t,n;
double f[N];
signed main()
{
	cin>>t;
	while(t--)
	{
		cin>>n;
		f[n]=0;
		for(int i=n-1;i>=0;i--)
			f[i]=(double)((n*1.0)/(n-i)+f[i+1]);
		printf("%.2lf\n",f[0]);
	}
	return 0;
}

P1365 WJMZBMR打osu! / Easy

我们设当前的最大连续的 o 长度为 \(len\),设 \(f[i]\) 为当前前 \(i\) 个 字符的期望得分。

当第 \(i\) 个字符为 x 的时候,我们连击中断,\(len\) 清零,得分和 \(i-1\) 的一样即 \(f[i]=f[i-1]\)

当第 \(i\) 个字符为 o 的时候,我们的连击次数加一,也就是 \(len\) 加一,得分可以根据 \((x+1)^{2}-x^{2}\) 来推导一下,可以得出 \(f[i]=f[i-1]+len\times 2+1\)

当第 \(i\) 个字符为 ? 的时候,我们有一半的概率获得 \(len\times 2+1\) 的分数,所以期望得分为 \(\frac{len\times 2+1}{2}\)\(len\) 有一半的概率清零,一半概率加一,所以期望长度为 \(\frac{len+1}{2}\)

code:

#include<bits/stdc++.h>
#define int long long
#define N 1000100
using namespace std;
int n;
char s[N];
double f[N],len;
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)cin>>s[i];
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='x')f[i]=f[i-1],len=0;
		if(s[i]=='o')f[i]=f[i-1]+2*len+1,len++;
		if(s[i]=='?')f[i]=f[i-1]+len+0.5,len=(len+1)*1.0/2;
	}
	printf("%.4lf\n",f[n]);
	return 0;
}