(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 }

 

posted @ 2018-09-13 11:31  DCDCBigBig  阅读(192)  评论(0编辑  收藏  举报