(2016北京集训十)【xsy1528】azelso - 概率期望dp
北京集训的题都是好题啊~~(于是我爆0了)
注意到一个重要的性质就是期望是线性的,也就是说每一段的期望步数可以直接加起来,那么dp求出每一段的期望就行了。。。
设$f_i$表示从$i$出发不回到$i$直接到达终点的概率,显然期望步数就是$\frac{1}{f_i}$;
考虑转移,设下一个事件概率为$p$,则
如果下一个事件是敌人:$f_i=f_{i+1}*p$
如果下一个事件是旗子:
$f_{i}=(1-p)*(1-f_{i+1})*(1+p*(1-f_{i+1})+p^{2}*(1-f_{i+1})^{2}+...)=(1-p)*\frac{1-f_{i+1}}{1-p*(1-f_{i+1})}$
第二个式子的表示的是下一次被打死并且没拿到旗子的概率;
但是还有一点小问题:$1-p*(1-f_{i+1})$可能为0
稍微变形一下:$\frac{f_{i+1}}{p}=(1-p)*f_{i+1}+p$
代码:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 #define eps 1e-9
9 #define mod 1000000007
10 using namespace std;
11 typedef long long ll;
12 ll h,n,ans,p[100001],a,b,f[100001],inv[100001],op[100001];
13 char ord[3];
14 ll fastpow(ll x,ll y){
15 int ret=1;
16 for(;y;y>>=1,x=x*x%mod){
17 if(y&1)ret=ret*x%mod;
18 }
19 return ret;
20 }
21 int main(){
22 scanf("%lld%lld",&h,&n);
23 for(int i=1;i<=n;i++){
24 scanf("%s",ord);
25 if(ord[0]=='F')op[i]=0;
26 else op[i]=1;
27 scanf("%lld%lld%lld",&p[i],&a,&b);
28 inv[i]=a*fastpow(b,mod-2)%mod;
29 }
30 f[n]=1;
31 ans=h-p[n];
32 for(int i=n-1;i>=0;i--){
33 if(op[i+1])f[i]=f[i+1]*fastpow(inv[i+1],mod-2)%mod;
34 else f[i]=((mod+1-inv[i+1])*f[i+1]%mod+inv[i+1])%mod;
35 ans=(ans+(p[i+1]-p[i]+mod)%mod*f[i]%mod)%mod;
36 }
37 printf("%lld",ans);
38 return 0;
39 }