[吐槽]
首先当然是要orzyww啦
以及orzyxq奇妙顺推很强qwq
嗯。。怎么说呢虽然说之前零零散散做了一些概d的题目但是总感觉好像并没有弄得比较明白啊。。(我的妈果然蒟蒻)
这题的话可以说是难得的一道搞得比较清楚的概d题目吧记录一下还是挺有意思的ovo
当然咯。。显然考场上并没有推出来。。嗯qwq
[题解]
看到说要求期望的距离,然后总的长度又被分成了一段一段的(各个事件)
所以就有一个比较直接的想法:将每一段期望走的次数算出来然后再乘上每一段的距离,加起来就是答案啦
那么现在问题来了怎么求期望走的次数
考虑定义
e[i]:第i个到第i+1个事件中间这段路程的经过次数的期望
f[i]:第i个事件发生后走到h,并且i到i+1中间这段路程只经过了一次的概率
根据定义我们可以得到:e[i]=1/f[i]
(然而为啥要这样搞呢。。嗯个人的理解是如果直接求期望会比较麻烦但是概率的话相对来说比较好写转移方程)
考虑转移
【奇妙套路】嗯概d的题目一般反着推会比较友善至于原因是啥。。还得求教各位dalao。。
所以这题我们也反着推咯
首先记第i+1个事件发生的概率为p,那么第i+1个事件有两种不同的情况:
1.打怪
如果说第i+1个事件要打怪,因为这段只能经过一次,所以显然打怪必须成功
(否则肯定会回到前面去,那么i到i+1就会经过不止一次了)
所以得到:i+1==X的话,f[i]=f[i+1]*p
2.插旗
但是如果说第i+1个事件是插旗,就会比较复杂了
因为现在只要求i到i+1这段经过1次,对后面的情况并没有限制,所以i+1以及后面的都可以经过很多次
换句话来说就是:只要第i+1这个位置插旗成功,后面的无论爆炸了多少次都没有关系,因为最前只能回到i+1这个位置
后面被打回来的概率的话,因为被打回来了所以显然i+1到i+2经过了不止一次,那么一次被打回来的概率就是1-f[i+1]
然后无论被打回来了多少次,最后一次肯定是要走到终点去的,所以最后要乘一个f[i+1]
那么我们就可以得到:
i+1==F的话
f[i]=f[i+1]+p*(1-f[i+1])*f[i+1]+(p*(1-f[i+1]))^2*f[i+1]+(p*(1-f[i+1]))^3*f[i+1]+...+(p*(1-f[i+1]))^n*f[i+1]
(爆炸0次+爆炸1次+爆炸2次+...+爆炸n次)
这里n->正无穷
考虑怎么算
但是发现插旗的情况,式子十分不友善。。所以就整理一下
先将f[i+1]提出来得到:
然后发现后面的一堆其实是这种形式:
我们记这个式子ans为a
那么a*x=
两式相减一下整理得到:
a=(1-x^n-1)/(1-x)
注意到,这里我们的x是一个概率,所以是小于1的,而n->正无穷,所以x^n-1是一个特别小的数可以直接忽略
所以得到:a=1/(1-x)
(mark:嗯有空可以去研究一下泰勒展开之类的)
然后就可以带进去算啦,得到:
f[i]=f[i+1]*1/(1-p*(1-f[i+1]))
考虑转成e[i]的转移方程
手头上两条式子:
i+1打怪:f[i]=f[i+1]*p
i+1插旗:f[i]=f[i+1]*1/(1-p*(1-f[i+1]))
将e[i]=1/f[i]带进去得到:
打怪:e[i]=e[i+1]/p
插旗:e[i]=(1-p)*e[i+1]+p
随后乘一下什么的算算答案就好
(所以说为啥这题我写了这么长的题解。。很迷啊。。果然太菜qwq)
[坑点]
除法的话用逆元就好啦
但是要多% (不然怕是要被续)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define MOD 1000000007 5 #define ll long long 6 using namespace std; 7 const int MAXN=1e5+10; 8 ll e[MAXN],p[MAXN],dis[MAXN]; 9 char op[MAXN]; 10 ll ans; 11 ll n,m; 12 ll ksm(ll x,int b); 13 ll inv(ll x); 14 15 int main() 16 { 17 char s[5]; 18 ll x,y; 19 scanf("%lld%lld",&n,&m); 20 for (int i=1;i<=m;++i) 21 { 22 scanf("%s%lld%lld%lld",s,&dis[i],&x,&y); 23 x=x%MOD; 24 y=y%MOD; 25 p[i]=x*inv(y)%MOD; 26 op[i]=s[0]; 27 } 28 e[m]=1; 29 for (int i=m-1;i>=0;--i) 30 { 31 if (op[i+1]==‘X‘) 32 e[i]=(e[i+1]*inv(p[i+1]))%MOD; 33 else 34 e[i]=((((1+MOD-p[i+1])%MOD)*e[i+1])%MOD+p[i+1])%MOD; 35 } 36 dis[0]=0; dis[m+1]=n; 37 for (int i=0;i<=m;++i) 38 ans=(ans+(((dis[i+1]-dis[i])%MOD)*e[i])%MOD)%MOD; 39 printf("%lld\n",ans); 40 } 41 42 ll ksm(ll x,int b) 43 { 44 ll ret=1,base=x; 45 while (b) 46 { 47 if (b&1) ret=(ret*base)%MOD; 48 base=(base*base)%MOD; 49 b>>=1; 50 } 51 return ret; 52 } 53 54 ll inv(ll x) 55 { 56 return ksm(x,MOD-2); 57 }