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,(in)
递推方程为: 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+1i+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]+bdp[0]=1kb,当 ( 1 − k ) < 1 0 − 6 (1-k)<10^{-6} (1k)<106即分母为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;
}