北京集训的题都是好题啊~~(于是我爆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+\cdots )=\frac{(1-p)*(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 }
原文地址:https://www.cnblogs.com/dcdcbigbig/p/9639551.html
时间: 2024-10-08 01:17:31