预备知识
定义
P
(
A
)
P(A)
P(A):事件A发生的概率;
E
(
A
)
E(A)
E(A):事件A的期望。
对于离散的事件
A
1
,
A
2
,
A
3
.
.
.
A
n
A_1,A_2,A_3...A_n
A1,A2,A3...An,则定义其期望为
P
(
A
)
×
A
P(A)\times A
P(A)×A,这里可以推出,若概率为
P
(
A
)
P(A)
P(A),设此概率为
p
q
\frac{p}{q}
qp,则不妨设样本容量为
q
q
q,则其发生次数为
p
p
p,从而其期望为
A
×
p
q
A \times\frac{p}{q}
A×qp,若其样本为等地位的,则其期望中
A
A
A可以省去,故有:
E
(
A
)
=
1
P
(
A
)
E(A)= \frac{1}{ P(A)}
E(A)=P(A)1。
从而可以以其解题。
题目
经典
下飞行棋,每次投骰子1-m,扔多少前进多少,求一开始在一,走到n的期望次数。(超过n也算走到n)
题解
最入门的题目。令
d
p
[
i
]
dp[i]
dp[i]表示距离终点还有
i
i
i步时的期望。那么显然
d
p
[
0
]
=
0
dp[0] = 0
dp[0]=0。为了方便起见,我们设
d
p
[
i
≤
0
]
=
0
dp[i \leq 0] = 0
dp[i≤0]=0。考虑转移,就是枚举这一次甩了多少,那么
d
p
[
i
]
=
1
+
1
m
∑
j
=
i
−
m
i
−
1
d
p
[
j
]
dp[i] = 1 + \frac{1}{m} \sum_{j = i - m}^{i - 1}dp[j]
dp[i]=1+m1j=i−m∑i−1dp[j]
化简得 d p [ i ] = m + 1 m d p [ i − 1 ] − 1 m d p [ i − m − 1 ] dp[i] = \frac{m + 1}{m} dp[i - 1] - \frac{1}{m}dp[i - m - 1] dp[i]=mm+1dp[i−1]−m1dp[i−m−1]。一个简单的做法是矩阵快速幂,复杂度 O ( m 3 l o g N ) O(m^3logN) O(m3logN)。注意到特殊性,转移只与两项有关,考虑一项贡献,为 ∑ x + ( m + 1 ) y = n − 1 ( m + 1 m ) x ( − 1 m ) y × C x + y x \sum_{x + (m + 1) y = n - 1}(\frac{m+1}{m})^{x}(-\frac{1}{m})^y \times C_{x+y}^{x} x+(m+1)y=n−1∑(mm+1)x(−m1)y×Cx+yx,那么 x = n − 1 − ( m + 1 ) ∗ y x = n - 1 - (m + 1) * y x=n−1−(m+1)∗y,从而原式
( m + 1 m ) n − 1 ∑ ( m + 1 ) y ≤ n − 1 [ ( m m + 1 ) m ( − 1 m ) ] y × C n − 1 − m y y (\frac{m+1}{m})^{n-1}\sum_{(m + 1) y \leq n - 1} [(\frac{m}{m+1})^{m} (-\frac{1}{m}) ] ^y \times C_{n - 1 - my}^{y} (mm+1)n−1(m+1)y≤n−1∑[(m+1m)m(−m1)]y×Cn−1−myy
bzoj 1426
有n种不同的邮票,皮皮想收集所有种类的邮票。唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是n种邮票中的哪一种是等概率的,概率均为1/n。但是由于凡凡也很喜欢邮票,所以皮皮购买第k张邮票需要支付k元钱。 现在皮皮手中没有邮票,皮皮想知道自己得到所有种类的邮票需要花费的钱数目的期望。
首先,我们先做一个入门版本的此题:
有
n
n
n种不同的邮票,皮皮想收集所有种类的邮票。唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是n种邮票中的哪一种是等概率的,概率均为
1
n
\frac{1}{n}
n1。现在皮皮手中没有邮票,皮皮想知道自己得到所有种类的邮票需要花费的钱数目的期望。
我们假设$f( i )
为
已
经
有
了
i
种
,
接
着
买
完
剩
下
为 已经有了 i 种,接着买完剩下
为已经有了i种,接着买完剩下(n-i)$种的期望,那么明显有
f
(
i
)
=
n
−
i
n
×
f
(
i
+
1
)
+
i
n
×
f
(
i
)
+
1
f(i)= \frac{ n - i } {n} \times f( i + 1 ) + \frac{i}{n} \times f( i ) + 1
f(i)=nn−i×f(i+1)+ni×f(i)+1;即化简得
f
(
i
)
=
f
(
i
+
1
)
+
n
−
i
n
f( i )=f( i + 1 )+\frac{n - i } {n}
f(i)=f(i+1)+nn−i。
为什么呢?这是因为当我们买下一张票的时候,有的概率买到新的一种,有概率买到原有的,而由于已经买了一张新的,那么买一张的新的概率就为1,所以由期望的公式得,要加上
1
1
1,有些题解说还要记录一个
g
(
i
)
g(i)
g(i)数组表示得到i种的概率,实际上没必要。原因马上讲。注意之前的定理,有
E
(
A
)
=
1
P
(
A
)
E(A)= \frac{1 }{P(A)}
E(A)=P(A)1,条件是事件地位平等,我们不妨这样,买一张买到一张新的概率是
n
−
i
n
\frac {n - i } { n}
nn−i那么由公式得其期望为
n
−
i
n
\frac{ n - i } {n}
nn−i,那么有全期望公式可得,
f
(
i
)
=
f
(
i
+
1
)
+
n
−
i
n
f( i ) = f( i+1 ) +\frac{ n - i}{n}
f(i)=f(i+1)+nn−i,与之前一模一样。
所以正解是
我们可以得到,对于这个
g
g
g,实际上是等概率的(都是一个收敛的级数,分布均匀),所以不用记录
g
g
g数组。而且,我们也更加可得
E
(
A
)
=
1
P
(
A
)
E(A)= \frac{1} {P(A)}
E(A)=P(A)1的重要性与巧妙性了。
好了,回到这道题,注意到每张邮票买的钱不一样,那么,我们可以理解为当概率相同时,权值不一样,所以期望不一样。所以也可以看成当权值相同时,概率不一样,所以这次要记录一个
g
g
g表示还要多少钱,当然也可以记概率,但更复杂。所以用
f
[
i
]
f[i]
f[i]表示已经拥有了
i
i
i张邮票,则期望还需要购买的邮票数。
f
[
i
]
=
f
[
i
]
×
i
n
+
f
[
i
+
1
]
×
n
−
i
n
+
1
f[i]=f[i] \times \frac{i}{n}+f[i+1] \times \frac{n-i}{n}+1
f[i]=f[i]×ni+f[i+1]×nn−i+1
$ f[i]=f[i+1]+\frac{n}{n-i};$
又有
$ g[i]=\frac{n-i}{n} \times (g[i+1]+f[i+1])+\frac{i}{n}\times( g[i]+f[i] )+1$
化简得
g
[
i
]
=
g
[
i
+
1
]
+
f
[
i
+
1
]
+
n
×
i
(
n
−
i
)
×
n
×
f
[
i
]
+
n
n
−
i
g[i]=g[i+1]+f[i+1]+\frac{n \times i}{ (n-i) \times n} \times f[i]+\frac {n} {n-i}
g[i]=g[i+1]+f[i+1]+(n−i)×nn×i×f[i]+n−in。
然后,就两个数组一起搞啊~~~。
(权限题,所以我也不确定正不正确,如果想要,找其他人吧。)
bzoj4832
(好题,以后玩炉石可以用)。题意是告诉你克苏恩的攻击力,你场上的随从状态(只有奴隶主,可能一血,二血,三血),问你克苏恩对英雄的伤害的期望。
题解
记录
d
p
[
i
]
[
m
]
[
n
]
[
k
]
dp[i][m][n][k]
dp[i][m][n][k]表示克苏恩i点攻击力,
1
—
3
1—3
1—3血分别有
m
,
n
,
k
m,n,k
m,n,k个时,把攻击打完受到的伤害(最好不要倒着定义成现在到打完还要受多少,时间会多一个常数)。然后,概率
d
p
dp
dp转一转就好了。注意这里的概率的分母为
1
+
m
+
n
+
k
1+m+n+k
1+m+n+k,因为还有个英雄。而且要注意,有可能造不出奴隶主了。(好题)
代码如下
#include<cstdio>
#include<algorithm>
using namespace std;
int i,m,n,k;
double dp[70][10][10][10];//已经受了这么多伤[m][n][k] m 1,n 2,k 3
int main()
{
for (int i = 1; i<=50 ;i++)
for (int m = 0;m <= 7;m++)
for (int n = 0; n <= 7 - m;n++)
for (int k = 0;k <= 7 - m - n ;k++)
{
int j = m + n + k;
double seg = 1.0 / (m + n + k + 1.0);
dp[i][m][n][k] += seg * ( dp[i-1][m][n][k] + 1.0);
if (m) dp[i][m][n][k] += (double)m * seg * dp[i-1][m-1][n][k];
if (n)
{
if (j<7) dp[i][m][n][k] += seg * (double)n * dp[i-1][m+1][n-1][k+1];
else dp[i][m][n][k] += seg * (double)n * dp[i-1][m+1][n-1][k];
}
if (k)
{
if (j<7) dp[i][m][n][k] += seg * (double)k * dp[i-1][m][n+1][k];
else dp[i][m][n][k] += seg * (double)k * dp[i-1][m][n+1][k-1];
}
}
int t;scanf("%d",&t);
while (t--)
{
scanf("%d%d%d%d",&i,&m,&n,&k);
printf("%.2lf\n",dp[i][m][n][k]);
}
return 0;
}
bzoj 1419##
翻钱,给定红钱个数,黑钱个数,一个一个翻,但是你只能知道还剩几个红,几个黑,翻到红就
+
1
s
+1s
+1s,黑就
−
1
s
-1s
−1s,可以随时不翻,然后就算成一种情况,求在最优策略下的期望。
题解
首先,最优策略明显就是当剩下的钱黑的多就不翻了,然后,就没别的策略了,拼
R
P
RP
RP了。设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]为剩下
i
i
i个红色,
j
j
j个黑色的期望,转移就是一般的转移,但是注意,我们得从后推
d
p
dp
dp,因为从前推我们不一定能推到最优策略(想想我们的最优策略,是看之后还要怎么翻,而明显,从后推时,
d
p
[
1
]
[
1
]
dp[1][1]
dp[1][1],
d
p
[
1
]
[
0
]
dp[1][0]
dp[1][0]这些我们都可以直接推出,所以从后推(我是指相对答案从后推,答案是
d
p
[
i
m
a
x
]
[
j
m
a
x
]
dp[i_{max}][j_{max}]
dp[imax][jmax]))。(还是水)。
代码如下(权限题,错了不怪我,我也没试过)
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
double dp[3][5010];
int r,b;
double k;
int main()
{
scanf("%d%d",&r,&b);
for (int i = 1;i <= r;i++)
{
dp[i%2][0] = i;
for (int j = 1 ;j <= b;j++)
{
double A = (double)i/(i+j),B = (double)j/(i+j);
k = A * ( dp[ (i-1)%2 ][j] + 1) + B* ( dp[i%2][j-1] -1);
dp[i%2][j] = max(0.0, k);
}
}
dp[r%2][b]=floor(dp[r%2][b]*=100000);
dp[r%2][b]/=1000000;
printf("%.6lf",dp[r%2][b]);
return 0;
}
bzoj1415##
(题太长了,自己去看吧…)
题解
组合题,但实际上并不难,只需要首先用
b
f
s
bfs
bfs搜一遍路径,用
x
[
i
]
[
j
]
x[i][j]
x[i][j]表示从
i
i
i走到
j
j
j下一步的点,由于要去最小的,所以还要记一个
d
i
s
dis
dis数组,然后判定距离加打擂台确定
x
[
i
]
[
j
]
x[i][j]
x[i][j]的值,接着就简单了,简单的期望
d
p
dp
dp转移,但是还要加上那只耗子不动的可能。
d
p
dp
dp的时候,由于是图上
d
p
dp
dp,最好写一个记忆化搜索,当然大佬可以写其他方法(膜)。(没那么水)(汤姆表示自己也想要一个这样的
G
P
S
GPS
GPS)。
代码如下:
#define f(x,y,z) for (int x=(y);x<=(z);x++)
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn =1005;
struct Edge{
int fr,to,next;
}edge[maxn*2];int line_cnt=0;
int head[maxn] , val[maxn]; int head_cnt = 0;
int x[maxn][maxn],dis[maxn][maxn];
double f[maxn][maxn];
int n,e;
int mou,cat;
void addedge(int f,int t)
{
int a = head[f];
edge[++line_cnt] = (Edge){f,t,a} ;
head [f] = line_cnt;
}
void adde(int f,int t)
{
addedge(f,t);
addedge(t,f);
}
void bfs(int start)//要记录距离
{
queue<int> q;
dis[start][start] =0;
q.push(start);
while (!q.empty())
{
int r = q.front();q.pop();int tmp = x[start][r];
for (int i = head[r]; i ;i = edge[i].next)
{
int u = edge[i].to;
if (dis [start][u]==-1 || (dis[start][r] +1 == dis[start][u] && tmp < x[start][u]))
{
dis[start][u] = dis[start][r] +1;
if (tmp) x[start][u] = tmp;else x[start][u] = u;
q.push(u);
}
}
}
}
double dp(int cc,int kk)//记忆化搜索
{
int n1 = x[cc][kk];
int n2 = x[n1][kk];
if (f[cc][kk] != -1) return f[cc][kk];
if (cc == kk) return f[cc][kk] = 0;
if (n1 == kk) return f[ cc ][kk] = 1;
if (n2 == kk) return f[ cc ][kk] = 1;
f[cc][kk] = 0;
for (int i = head[kk]; i ;i = edge[i].next)
{
int u = edge[i].to;
f[cc][kk] += dp( n2 , u );
}
f[cc][kk] = ( f[cc][kk] + dp( n2 , kk) ) / (double) ( val[kk] + 1 ) +1;
return f[cc][kk];
}
int main()
{
scanf("%d%d",&n,&e);
scanf("%d%d",&cat,&mou);
int ua,ub;
memset(dis,-1,sizeof dis);
memset(val,0,sizeof val);
for (int i = 1;i<=n;i++)
for (int j = 1;j<=n;j++)
f[i][j]=-1;
for (int i=1;i<=e;i++)
{
scanf("%d%d",&ua,&ub);
val[ua]++;val[ub]++;
adde( ua , ub);
}
for (int i = 1 ;i<=n;i++) {bfs(i);x[i][i]=i;}
printf("%.3lf", dp(cat , mou));
return 0;
}
树上期望:
- 树上随机游走的期望(求从根节点第一次到其他节点的期望步数):
接着看
G
[
i
]
G[i]
G[i],我们有从
f
a
fa
fa走到一个错误的儿子,走到
f
a
fa
fa的父亲,走到
i
i
i这三种情况。
G
[
i
]
=
1
+
G
[
f
a
]
+
G
[
i
]
+
1
+
∑
F
[
b
r
o
t
h
e
r
]
+
G
[
i
]
+
1
d
[
f
a
]
G[i]=\frac{1+G[fa]+G[i]+1+ \sum F[brother]+G[i]+1}{d[fa]}
G[i]=d[fa]1+G[fa]+G[i]+1+∑F[brother]+G[i]+1,
化简得
G
[
i
]
=
G
[
f
a
]
+
d
[
f
a
]
+
∑
F
[
b
r
o
t
h
e
r
]
G[i]=G[fa]+d[fa]+\sum F[brother]
G[i]=G[fa]+d[fa]+∑F[brother]。
即:
F
[
f
a
]
−
F
[
i
]
=
d
[
f
a
]
+
∑
F
[
b
r
o
t
h
e
r
]
F[fa] - F[i] = d[fa]+\sum F[brother]
F[fa]−F[i]=d[fa]+∑F[brother]。
G
[
i
]
=
G
[
f
a
]
+
F
[
f
a
]
−
F
[
i
]
G[i] = G[fa]+F[fa]-F[i]
G[i]=G[fa]+F[fa]−F[i]。
- 更简单的方法:
上面的实际上就足够了,复杂度是
O
(
n
)
O(n)
O(n)的,常数为
2
2
2(两遍
d
f
s
dfs
dfs),但是还有更好的,一边
d
f
s
dfs
dfs就可以搞定,而且更简单。
不仿设第
i
i
i个点的期望是
a
n
s
[
i
]
ans[i]
ans[i],那么有
a
n
s
[
i
]
=
a
n
s
[
f
a
]
+
G
[
i
]
ans[i] = ans[fa] + G[i]
ans[i]=ans[fa]+G[i](
G
[
i
]
G[i]
G[i]就是之前的东西)。
那么这个
G
[
i
]
G[i]
G[i]由之前的式子可得
G
[
i
]
=
G
[
f
a
]
+
d
[
f
a
]
+
∑
F
[
b
r
o
t
h
e
r
]
G[i] = G[fa]+d[fa]+\sum F[brother]
G[i]=G[fa]+d[fa]+∑F[brother]
,
G
[
f
a
]
G[fa]
G[fa]又是什么呢?
再迭代可得
G
[
f
a
]
=
G
[
g
r
a
n
d
f
a
]
+
d
[
g
r
a
n
d
f
a
]
+
∑
F
[
b
r
o
t
h
e
r
]
G[fa]=G[grandfa]+d[grandfa]+\sum F[brother]
G[fa]=G[grandfa]+d[grandfa]+∑F[brother]。
如此下去,直到
r
o
o
t
,
G
[
r
o
o
t
]
=
0
root,G[root]=0
root,G[root]=0,将这些式子加起来,可得
G
[
i
]
=
∑
d
[
a
n
c
e
s
t
e
r
]
(
除
了
i
)
+
∑
∑
F
[
b
r
o
t
h
e
r
]
G[i] = \sum d[ancester](除了i) +\sum \sum F[brother]
G[i]=∑d[ancester](除了i)+∑∑F[brother](这个双segma表示的是对于每一个
a
n
c
e
s
t
e
r
ancester
ancester而言,其除了
i
i
i的祖先的儿子的
F
F
F之和)。
注意到
F
[
j
]
=
d
[
j
]
+
∑
F
[
s
o
n
]
F[j] = d[j] + \sum F[son]
F[j]=d[j]+∑F[son]
,那么对于一个
F
[
j
]
F[j]
F[j],我们递归可以得到
F
[
j
]
=
以
j
为
根
的
子
树
的
度
数
总
和
+
1
F[j]= 以j为根的子树的度数总和+1
F[j]=以j为根的子树的度数总和+1(加一是因为i还有一个特殊的度是通向其父亲的)
,那么这个
f
[
j
]
+
d
[
j
]
f[j]+d[j]
f[j]+d[j]不就是这个树的度数
+
1
+1
+1。
又因为其度数中,一条边算了两次(除了j通向其父亲的),所以这棵树的度数=$2\times
其
点
数
其点数
其点数-1
(
不
忘
特
殊
边
只
算
过
一
次
)
,
所
以
这
个
式
子
是
以
(不忘特殊边只算过一次),所以这个式子是以
(不忘特殊边只算过一次),所以这个式子是以j
为
根
的
的
子
树
的
大
小
,
出
了
为根的的子树的大小,出了
为根的的子树的大小,出了j
走
向
走向
走向i
的
那
颗
子
树
,
所
以
求
和
之
和
是
长
这
样
的
:
!
[
这
里
写
图
片
描
述
]
(
h
t
t
p
:
/
/
i
m
g
.
b
l
o
g
.
c
s
d
n
.
n
e
t
/
20171103163348544
?
w
a
t
e
r
m
a
r
k
/
2
/
t
e
x
t
/
a
H
R
0
c
D
o
v
L
2
J
s
b
2
c
u
Y
3
N
k
b
i
5
u
Z
X
Q
v
R
G
V
t
b
25
f
U
m
l
l
b
W
F
u
/
f
o
n
t
/
5
a
6
L
5
L
2
T
/
f
o
n
t
s
i
z
e
/
400
/
f
i
l
l
/
I
0
J
B
Q
k
F
C
M
A
=
=
/
d
i
s
s
o
l
v
e
/
70
/
g
r
a
v
i
t
y
/
S
o
u
t
h
E
a
s
t
)
蛤
?
那
不
就
是
除
了
的那颗子树,所以求和之和是长这样的: ![这里写图片描述](https://img-blog.csdn.net/20171103163348544?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRGVtb25fUmllbWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 蛤?那不就是除了
的那颗子树,所以求和之和是长这样的:![这里写图片描述](http://img.blog.csdn.net/20171103163348544?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRGVtb25fUmllbWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)蛤?那不就是除了i
以
外
的
树
的
大
小
的
两
倍
?
但
是
我
们
还
是
要
注
意
,
根
节
点
没
有
头
上
的
那
根
,
所
以
还
要
减
一
,
所
以
将
每
个
以外的树的大小的两倍?但是我们还是要注意,根节点没有头上的那根,所以还要减一,所以将每个
以外的树的大小的两倍?但是我们还是要注意,根节点没有头上的那根,所以还要减一,所以将每个\sum F[son]与d[ancester]KaTeX parse error: Expected 'EOF', got '#' at position 33: …ize=4 color = #̲0000FF>G[i] = 2(n-Size[i])+1$ 。
从而 a n s [ i ] = a n s [ f a ] + 2 ( n − s i z e [ i ] ) + 1 ans[i] = ans[fa] + 2(n-size[i])+1 ans[i]=ans[fa]+2(n−size[i])+1。那这个就可以一遍搞定了。
- 另解:
对于这个式子证明还有一个感性的理解,因为我们想, G [ i ] G[i] G[i]而言,从 f a fa fa走到 i i i的期望,我们不管什么树,什么路径,我们这样想,从 n n n个节点中随便选一个,如果选到 i i i及其子树上的点,那么肯定走到过 i i i,反之,就没走到过,所以选到其子树概率是 s i z e n \frac {size}{n} nsize,又因为概率等于期望的倒数,所以有 G [ i ] = 2 ( n − s i z e [ i ] ) + 1 G[i]=2(n-size[i])+1 G[i]=2(n−size[i])+1。(乱证的,请自行跳过。)
连续样本的期望
作为一个数竞党,再发一个对连续样本期望的求法(实际上就是积分一下就好了)(转自百度百科):
最后要说的
好吧,最后说一下,这是我的第一篇博客,其中一些想法借鉴了许多大犇的题解,所以如果发现有雷同,那很可能是我从前看过的,然后整理了一下吧…