时间流逝(flow)——概率题

这篇博客探讨了一个概率和动态规划相结合的数学问题。在这个问题中,一个生物通过吞噬周围生物获得能量,但有时会遭遇果冻鱼的攻击。生物的能量值达到一定阈值后可以进化到更强大的模式。博客介绍了如何使用动态规划来计算预计需要多少天才能达到这个阈值,以及在过程中遇到果冻鱼的概率如何影响这一过程。文章提供了详细的算法实现,并给出了样例输入和输出,适合对概率论和算法感兴趣的读者阅读。
摘要由CSDN通过智能技术生成

时间流逝(flow)

Time Limits: 1s Memory Limits: 256MB

Description
生活可以很简单。可以探索水底世界的神秘,也可以去发现奇特新生物,亦或踏上一段新生的旅程。在必须要迎接挑战或跟周围的生物进行生存争夺之前,享受自由的飞翔。此时你会觉得生活是如此美好。
像蛇喜欢吃浮游生物一样(哦,我好像忘记告诉你这个常识),每天,你可以吃一些你周围的基础生物,然后会在你的尾巴上得到一个能量圈。你将会有好多种不同的能量圈,每一个都会被赋予一个能量。你可以拥有多个同种的能量圈,但是对于新得到的能量圈,它的能量不能大于你已拥有的任何一个能量圈。在前面规则的前提下,获得新的能量圈的种类的概率是一样的。一天天过去,你得到越来越多的能量,开始了进化演变。
但是你也有自己的问题,有时你会面对邪恶的果冻鱼。它会追着你咬你,你不得不扔出最小能量值的能量圈然后赶忙逃跑。在这种情况下,你不会有任何的胃口了,因此这天你将不再得到任何能量圈。幸好,当你没有任何能量圈的时候,果冻鱼就算看见你也不会追着你,此时你可以好好地享用美食。
你听说当你的总的能量值超过了某个阈值之后,可以进化成强大模式并能够吃掉果冻鱼。是时候反击了!下面是本题的问题:预计要过多少天你才能进化成强大模式?(第一天默认你没有任何能量圈)

Input
输入包含多个测例。对每个测例会有两行。第一行是一个浮点数P,一个整数T和一个整数N。P是每天遇到果冻鱼的概率,T是阈值。第二行是N个不同的正整数,表示每一种能量圈的能量值。

Output
对于每个测例,输出一行表示预计要过多少天你的能量值能够超过阈值,四舍五入到三位小数。

Sample Input

0.5 0 1
1
0.5 1 2
1 2

Sample Output

1.000
2.000

Hint
对于所有数据,0.1≤P≤0.9,1≤T≤50,1≤N≤30。


一道概率题。
这种最不走运能够走∞步,想用无穷级数,因为走法太恶心,所以行不通。
然而解决期望的另一种是DP设期望,然后得出方程。

将能量值排序。

设 fx,y 表示由状态{能量总和为x,最小能量环为第y小}到终点 x′>T 的期望天数
那么 fx,y 有 p′ 的概率被吃掉一个环( p′=p(x>0)  p′=0(x=0) ),即有 p′ 的概率由 ffa+1 转移来;有 1−p′ 的概率往下走,也就是说有 1−p′ 的概率由 fai,i+1i 转移过来。
即:

fx,y=p′(ffa+1)+1−p′y∑i=1yfx+ai,i+1

考虑递归,每个状态返回用 ffa 表示 fx,y 的方法,它是个一元一次多项式。

那么用 fx,y 表示 fx+ai,i 后, 1−p′y∑yi=1fx+ai,i+1 也可以用 fx,y 表示,设其为 Afx,y+B

原式化为

fx,y=p′ffa+p′+Afx,y+B

解方程

fx,y=p′1−Affa+p′+B1−A


这样就表示好了。

递归 f(0,n) ,这时 ffa=0

#include<cstring>
#include<cstdio>
#include<algorithm>
#define db double

using namespace std;

int n,lim,v[40];
db p;
struct fc{db a,b;};

fc operator+(fc a,fc b){return (fc){a.a+b.a,a.b+b.b};}
fc operator+(fc a,db b){return (fc){a.a,a.b+b};}
fc operator*(fc a,db b){return (fc){a.a*b,a.b*b};}

fc P(int s,int x){
    if(s>lim)return (fc){0,0};
    fc ex=(fc){0,0};db _p=(s?1-p:1)/(db)x;
    for(int i=1;i<=x;i++)ex=ex+(P(s+v[i],i)+1)*_p;
    if(s){
        db t=1-ex.a;return (fc){p/t,(ex.b+p)/t};
    }return (fc){0,ex.b/(1-ex.a)};
}

int main(){
    freopen("flow.in","r",stdin);
    freopen("flow.out","w",stdout);
    while(~scanf("%lf %d %d",&p,&lim,&n)){
        for(int i=1;i<=n;i++)scanf("%d",&v[i]);sort(v+1,v+n+1);
        printf("%.3lf\n",P(0,n).b);
    }
    fclose(stdin);fclose(stdout);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃鸳鸯锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值