期望入门
什么是期望
当我们在做一些题目的时候可能会 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$$
或者再看另一个例子。
有一个商场开设了一个活动,每一个用户可以转动两个转盘来获取奖金,如下图:
技术问题凑合看
一个人可以重复获奖,每人第一个转盘可以转两次,第二个转盘可以转三次
第一个转盘获奖的概率为 \(\frac{1}{7}\),第二个转盘获奖的概率为 \(\frac{1}{9}\)
那么我们可以得到每个用户得到的奖金的期望为
(因为除不尽所以保留了四位小数)
例题
P3802 小魔女帕琪
设魔法的总数为 \(tot\),每一个魔法的个数为 \(a_{1}\) 到 \(a_{7}\)。
先考虑当拿了前七个刚好为 \(1,2,3,4,5,6,7\) 放了一次大的情况,概率为:
也就是
那么我们先取哪一种的顺序的没有关系的,只要前七个的魔法是不同的,那么触发的概率就是上面的柿子。
所以我们前七个放出大招的可能就是这个固定的值,而可能性就是这七个魔法的全排列个数也就是 \(7!\),所以我们前七个能放出来大招的期望就是
而我们的总长度为 \(tot\),也就是说有 \(tot-6\) 个的七个连续的魔法,所以答案还要再乘以 \(tot-6\),所以最终答案为
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 [国家集训队]单选错位
这道题目我们需要分类讨论一下。
-
当前的 \(a_{i}=a_{i+1}\),那么这个时候第 \(i\) 道题目做对的概率就是 \(\frac{1}{a_{i}}=\frac{1}{a_{i+1}}\)
-
当前的 \(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}}\)
-
当前的 \(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})}\)
最终答案为
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]\) 次。
由于我们掷了这一次,所以无论结果是什么,都是要加一,所以得出转移方程
合并同类项后得
通分得
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;
}
本文来自博客园,作者:北烛青澜,转载请注明原文链接:https://www.cnblogs.com/Multitree/p/17347985.html
The heart is higher than the sky, and life is thinner than paper.