F - Sugoroku2 (期望dp)
概率和期望常用的算法是dp
。
思路
本题是从后往前dp,设
d
p
[
i
]
dp[i]
dp[i]为从
i
i
i走到
n
n
n的期望,目标是
d
p
[
0
]
dp[0]
dp[0],已知
d
p
[
i
]
=
0
,
(
i
≥
n
)
dp[i]=0,(i\ge n)
dp[i]=0,(i≥n)。
递推方程为:
d
p
[
i
]
=
∑
j
=
i
+
1
i
+
m
d
p
[
j
]
m
+
1
dp[i]=\dfrac{\sum\limits_{j=i+1}^{i+m} dp[j]}{m}+1
dp[i]=mj=i+1∑i+mdp[j]+1
如果位置
j
j
j不能走,则
d
p
[
j
]
=
d
p
[
0
]
dp[j]=dp[0]
dp[j]=dp[0],因此我们只需要所有的
d
p
[
i
]
dp[i]
dp[i]都表示成
k
×
d
p
[
0
]
+
b
k\times dp[0]+b
k×dp[0]+b的形式,最终我们只需求解
d
p
[
0
]
=
k
×
d
p
[
0
]
+
b
→
d
p
[
0
]
=
b
1
−
k
dp[0]=k\times dp[0]+b\rightarrow dp[0]=\dfrac{b}{1-k}
dp[0]=k×dp[0]+b→dp[0]=1−kb,当
(
1
−
k
)
<
1
0
−
6
(1-k)<10^{-6}
(1−k)<10−6即分母为0是无解的。
时间复杂度: O ( n ) O(n) O(n)
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
struct node{
long double k,b;
}f[N],suf[N];
node operator +(node i,node j){
return {i.k+j.k,i.b+j.b};
}
node operator -(node i,node j){
return {i.k-j.k,i.b-j.b};
}
node operator /(node i,double j){
return {i.k/j,i.b/j};
}
int n,m,k;
bitset<N>vis;
int main(){
scanf("%d%d%d",&n,&m,&k);for(int i=1,x;i<=k;i++) scanf("%d",&x),vis[x]=1;
for(int i=n-1;~i;i--){
if(vis[i]) f[i]={1,0};
else f[i]=(suf[i+1]-suf[i+m+1])/m+(node){0,1};
suf[i]=suf[i+1]+f[i];
}
if(fabs(f[0].k-1)<1e-6) puts("-1");
else printf("%.4Lf\n",f[0].b/(1-f[0].k));
return 0;
}